builtins.toJSON: fix __toString usage

(cherry picked from commit e583df52800b4baa1564b027fe3b83a21756c2cc)
This commit is contained in:
Robin Gloster 2019-10-27 10:15:51 +01:00 committed by Eelco Dolstra
parent 6c90e3b9ac
commit 3130aafd01
5 changed files with 29 additions and 8 deletions

View file

@ -1568,6 +1568,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)
{
@ -1586,13 +1599,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);
}

View file

@ -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,

View file

@ -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;

View file

@ -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\"}"

View file

@ -9,4 +9,5 @@ builtins.toJSON
h = [ "a" [ "b" { "foo\nbar" = {}; } ] ];
i = 1 + 2;
j = 1.44;
k = { __toString = self: self.a; a = "foo"; };
}