aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libexpr/eval.cc23
-rw-r--r--src/libexpr/eval.hh4
-rw-r--r--src/libexpr/value-to-json.cc7
-rw-r--r--tests/lang/eval-okay-tojson.exp2
-rw-r--r--tests/lang/eval-okay-tojson.nix1
5 files changed, 29 insertions, 8 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index f60e8d3ab..dc16d20b5 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -1567,6 +1567,19 @@ bool EvalState::isDerivation(Value & v)
}
+std::optional<string> EvalState::tryAttrsToString(const Pos & pos, Value & v,
+ PathSet & context, bool coerceMore, bool copyToStore)
+{
+ auto i = v.attrs->find(sToString);
+ if (i != v.attrs->end()) {
+ Value v1;
+ callFunction(*i->value, v, v1, pos);
+ return coerceToString(pos, v1, context, coerceMore, copyToStore);
+ }
+
+ return {};
+}
+
string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
bool coerceMore, bool copyToStore)
{
@@ -1585,13 +1598,11 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
}
if (v.type == tAttrs) {
- auto i = v.attrs->find(sToString);
- if (i != v.attrs->end()) {
- Value v1;
- callFunction(*i->value, v, v1, pos);
- return coerceToString(pos, v1, context, coerceMore, copyToStore);
+ auto maybeString = tryAttrsToString(pos, v, context, coerceMore, copyToStore);
+ if (maybeString) {
+ return *maybeString;
}
- i = v.attrs->find(sOutPath);
+ auto i = v.attrs->find(sOutPath);
if (i == v.attrs->end()) throwTypeError("cannot coerce a set to a string, at %1%", pos);
return coerceToString(pos, *i->value, context, coerceMore, copyToStore);
}
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index 22472fd72..61ee4a73b 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -9,6 +9,7 @@
#include "function-trace.hh"
#include <map>
+#include <optional>
#include <unordered_map>
@@ -196,6 +197,9 @@ public:
set with attribute `type = "derivation"'). */
bool isDerivation(Value & v);
+ std::optional<string> tryAttrsToString(const Pos & pos, Value & v,
+ PathSet & context, bool coerceMore = false, bool copyToStore = true);
+
/* String coercion. Converts strings, paths and derivations to a
string. If `coerceMore' is set, also converts nulls, integers,
booleans and lists to a string. If `copyToStore' is set,
diff --git a/src/libexpr/value-to-json.cc b/src/libexpr/value-to-json.cc
index 72e413e44..5fe8570ad 100644
--- a/src/libexpr/value-to-json.cc
+++ b/src/libexpr/value-to-json.cc
@@ -40,7 +40,12 @@ void printValueAsJSON(EvalState & state, bool strict,
break;
case tAttrs: {
- Bindings::iterator i = v.attrs->find(state.sOutPath);
+ auto maybeString = state.tryAttrsToString(noPos, v, context, false, false);
+ if (maybeString) {
+ out.write(*maybeString);
+ break;
+ }
+ auto i = v.attrs->find(state.sOutPath);
if (i == v.attrs->end()) {
auto obj(out.object());
StringSet names;
diff --git a/tests/lang/eval-okay-tojson.exp b/tests/lang/eval-okay-tojson.exp
index 33588493f..e92aae323 100644
--- a/tests/lang/eval-okay-tojson.exp
+++ b/tests/lang/eval-okay-tojson.exp
@@ -1 +1 @@
-"{\"a\":123,\"b\":-456,\"c\":\"foo\",\"d\":\"foo\\n\\\"bar\\\"\",\"e\":true,\"f\":false,\"g\":[1,2,3],\"h\":[\"a\",[\"b\",{\"foo\\nbar\":{}}]],\"i\":3,\"j\":1.44}"
+"{\"a\":123,\"b\":-456,\"c\":\"foo\",\"d\":\"foo\\n\\\"bar\\\"\",\"e\":true,\"f\":false,\"g\":[1,2,3],\"h\":[\"a\",[\"b\",{\"foo\\nbar\":{}}]],\"i\":3,\"j\":1.44,\"k\":\"foo\"}"
diff --git a/tests/lang/eval-okay-tojson.nix b/tests/lang/eval-okay-tojson.nix
index c046ba4ae..ce67943be 100644
--- a/tests/lang/eval-okay-tojson.nix
+++ b/tests/lang/eval-okay-tojson.nix
@@ -9,4 +9,5 @@ builtins.toJSON
h = [ "a" [ "b" { "foo\nbar" = {}; } ] ];
i = 1 + 2;
j = 1.44;
+ k = { __toString = self: self.a; a = "foo"; };
}