forked from lix-project/lix
Merge pull request #8566 from inclyc/nixd/value-print-depth
libexpr: extend `Value::print` to allow limited depth
This commit is contained in:
commit
7b39a388b3
|
@ -96,10 +96,15 @@ RootValue allocRootValue(Value * v)
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::print(const SymbolTable &symbols, std::ostream &str,
|
void Value::print(const SymbolTable &symbols, std::ostream &str,
|
||||||
std::set<const void *> * seen) const
|
std::set<const void *> *seen, int depth) const
|
||||||
|
|
||||||
{
|
{
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
|
|
||||||
|
if (depth <= 0) {
|
||||||
|
str << "«too deep»";
|
||||||
|
return;
|
||||||
|
}
|
||||||
switch (internalType) {
|
switch (internalType) {
|
||||||
case tInt:
|
case tInt:
|
||||||
str << integer;
|
str << integer;
|
||||||
|
@ -123,7 +128,7 @@ void Value::print(const SymbolTable & symbols, std::ostream & str,
|
||||||
str << "{ ";
|
str << "{ ";
|
||||||
for (auto & i : attrs->lexicographicOrder(symbols)) {
|
for (auto & i : attrs->lexicographicOrder(symbols)) {
|
||||||
str << symbols[i->name] << " = ";
|
str << symbols[i->name] << " = ";
|
||||||
i->value->print(symbols, str, seen);
|
i->value->print(symbols, str, seen, depth - 1);
|
||||||
str << "; ";
|
str << "; ";
|
||||||
}
|
}
|
||||||
str << "}";
|
str << "}";
|
||||||
|
@ -139,7 +144,7 @@ void Value::print(const SymbolTable & symbols, std::ostream & str,
|
||||||
str << "[ ";
|
str << "[ ";
|
||||||
for (auto v2 : listItems()) {
|
for (auto v2 : listItems()) {
|
||||||
if (v2)
|
if (v2)
|
||||||
v2->print(symbols, str, seen);
|
v2->print(symbols, str, seen, depth - 1);
|
||||||
else
|
else
|
||||||
str << "(nullptr)";
|
str << "(nullptr)";
|
||||||
str << " ";
|
str << " ";
|
||||||
|
@ -181,11 +186,10 @@ void Value::print(const SymbolTable & symbols, std::ostream & str,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Value::print(const SymbolTable &symbols, std::ostream &str,
|
||||||
void Value::print(const SymbolTable & symbols, std::ostream & str, bool showRepeated) const
|
bool showRepeated, int depth) const {
|
||||||
{
|
|
||||||
std::set<const void *> seen;
|
std::set<const void *> seen;
|
||||||
print(symbols, str, showRepeated ? nullptr : &seen);
|
print(symbols, str, showRepeated ? nullptr : &seen, depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pretty print types for assertion errors
|
// Pretty print types for assertion errors
|
||||||
|
|
236
src/libexpr/tests/value/print.cc
Normal file
236
src/libexpr/tests/value/print.cc
Normal file
|
@ -0,0 +1,236 @@
|
||||||
|
#include "tests/libexpr.hh"
|
||||||
|
|
||||||
|
#include "value.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
using namespace testing;
|
||||||
|
|
||||||
|
struct ValuePrintingTests : LibExprTest
|
||||||
|
{
|
||||||
|
template<class... A>
|
||||||
|
void test(Value v, std::string_view expected, A... args)
|
||||||
|
{
|
||||||
|
std::stringstream out;
|
||||||
|
v.print(state.symbols, out, args...);
|
||||||
|
ASSERT_EQ(out.str(), expected);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(ValuePrintingTests, tInt)
|
||||||
|
{
|
||||||
|
Value vInt;
|
||||||
|
vInt.mkInt(10);
|
||||||
|
test(vInt, "10");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValuePrintingTests, tBool)
|
||||||
|
{
|
||||||
|
Value vBool;
|
||||||
|
vBool.mkBool(true);
|
||||||
|
test(vBool, "true");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValuePrintingTests, tString)
|
||||||
|
{
|
||||||
|
Value vString;
|
||||||
|
vString.mkString("some-string");
|
||||||
|
test(vString, "\"some-string\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValuePrintingTests, tPath)
|
||||||
|
{
|
||||||
|
Value vPath;
|
||||||
|
vPath.mkString("/foo");
|
||||||
|
test(vPath, "\"/foo\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValuePrintingTests, tNull)
|
||||||
|
{
|
||||||
|
Value vNull;
|
||||||
|
vNull.mkNull();
|
||||||
|
test(vNull, "null");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValuePrintingTests, tAttrs)
|
||||||
|
{
|
||||||
|
Value vOne;
|
||||||
|
vOne.mkInt(1);
|
||||||
|
|
||||||
|
Value vTwo;
|
||||||
|
vTwo.mkInt(2);
|
||||||
|
|
||||||
|
BindingsBuilder builder(state, state.allocBindings(10));
|
||||||
|
builder.insert(state.symbols.create("one"), &vOne);
|
||||||
|
builder.insert(state.symbols.create("two"), &vTwo);
|
||||||
|
|
||||||
|
Value vAttrs;
|
||||||
|
vAttrs.mkAttrs(builder.finish());
|
||||||
|
|
||||||
|
test(vAttrs, "{ one = 1; two = 2; }");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValuePrintingTests, tList)
|
||||||
|
{
|
||||||
|
Value vOne;
|
||||||
|
vOne.mkInt(1);
|
||||||
|
|
||||||
|
Value vTwo;
|
||||||
|
vTwo.mkInt(2);
|
||||||
|
|
||||||
|
Value vList;
|
||||||
|
state.mkList(vList, 5);
|
||||||
|
vList.bigList.elems[0] = &vOne;
|
||||||
|
vList.bigList.elems[1] = &vTwo;
|
||||||
|
vList.bigList.size = 3;
|
||||||
|
|
||||||
|
test(vList, "[ 1 2 (nullptr) ]");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValuePrintingTests, vThunk)
|
||||||
|
{
|
||||||
|
Value vThunk;
|
||||||
|
vThunk.mkThunk(nullptr, nullptr);
|
||||||
|
|
||||||
|
test(vThunk, "<CODE>");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValuePrintingTests, vApp)
|
||||||
|
{
|
||||||
|
Value vApp;
|
||||||
|
vApp.mkApp(nullptr, nullptr);
|
||||||
|
|
||||||
|
test(vApp, "<CODE>");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValuePrintingTests, vLambda)
|
||||||
|
{
|
||||||
|
Value vLambda;
|
||||||
|
vLambda.mkLambda(nullptr, nullptr);
|
||||||
|
|
||||||
|
test(vLambda, "<LAMBDA>");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValuePrintingTests, vPrimOp)
|
||||||
|
{
|
||||||
|
Value vPrimOp;
|
||||||
|
vPrimOp.mkPrimOp(nullptr);
|
||||||
|
|
||||||
|
test(vPrimOp, "<PRIMOP>");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValuePrintingTests, vPrimOpApp)
|
||||||
|
{
|
||||||
|
Value vPrimOpApp;
|
||||||
|
vPrimOpApp.mkPrimOpApp(nullptr, nullptr);
|
||||||
|
|
||||||
|
test(vPrimOpApp, "<PRIMOP-APP>");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValuePrintingTests, vExternal)
|
||||||
|
{
|
||||||
|
struct MyExternal : ExternalValueBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string showType() const override
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
std::string typeOf() const override
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
virtual std::ostream & print(std::ostream & str) const override
|
||||||
|
{
|
||||||
|
str << "testing-external!";
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
} myExternal;
|
||||||
|
Value vExternal;
|
||||||
|
vExternal.mkExternal(&myExternal);
|
||||||
|
|
||||||
|
test(vExternal, "testing-external!");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValuePrintingTests, vFloat)
|
||||||
|
{
|
||||||
|
Value vFloat;
|
||||||
|
vFloat.mkFloat(2.0);
|
||||||
|
|
||||||
|
test(vFloat, "2");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValuePrintingTests, vBlackhole)
|
||||||
|
{
|
||||||
|
Value vBlackhole;
|
||||||
|
vBlackhole.mkBlackhole();
|
||||||
|
test(vBlackhole, "«potential infinite recursion»");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValuePrintingTests, depthAttrs)
|
||||||
|
{
|
||||||
|
Value vOne;
|
||||||
|
vOne.mkInt(1);
|
||||||
|
|
||||||
|
Value vTwo;
|
||||||
|
vTwo.mkInt(2);
|
||||||
|
|
||||||
|
BindingsBuilder builder(state, state.allocBindings(10));
|
||||||
|
builder.insert(state.symbols.create("one"), &vOne);
|
||||||
|
builder.insert(state.symbols.create("two"), &vTwo);
|
||||||
|
|
||||||
|
Value vAttrs;
|
||||||
|
vAttrs.mkAttrs(builder.finish());
|
||||||
|
|
||||||
|
BindingsBuilder builder2(state, state.allocBindings(10));
|
||||||
|
builder2.insert(state.symbols.create("one"), &vOne);
|
||||||
|
builder2.insert(state.symbols.create("two"), &vTwo);
|
||||||
|
builder2.insert(state.symbols.create("nested"), &vAttrs);
|
||||||
|
|
||||||
|
Value vNested;
|
||||||
|
vNested.mkAttrs(builder2.finish());
|
||||||
|
|
||||||
|
test(vNested, "{ nested = «too deep»; one = «too deep»; two = «too deep»; }", false, 1);
|
||||||
|
test(vNested, "{ nested = { one = «too deep»; two = «too deep»; }; one = 1; two = 2; }", false, 2);
|
||||||
|
test(vNested, "{ nested = { one = 1; two = 2; }; one = 1; two = 2; }", false, 3);
|
||||||
|
test(vNested, "{ nested = { one = 1; two = 2; }; one = 1; two = 2; }", false, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValuePrintingTests, depthList)
|
||||||
|
{
|
||||||
|
Value vOne;
|
||||||
|
vOne.mkInt(1);
|
||||||
|
|
||||||
|
Value vTwo;
|
||||||
|
vTwo.mkInt(2);
|
||||||
|
|
||||||
|
BindingsBuilder builder(state, state.allocBindings(10));
|
||||||
|
builder.insert(state.symbols.create("one"), &vOne);
|
||||||
|
builder.insert(state.symbols.create("two"), &vTwo);
|
||||||
|
|
||||||
|
Value vAttrs;
|
||||||
|
vAttrs.mkAttrs(builder.finish());
|
||||||
|
|
||||||
|
BindingsBuilder builder2(state, state.allocBindings(10));
|
||||||
|
builder2.insert(state.symbols.create("one"), &vOne);
|
||||||
|
builder2.insert(state.symbols.create("two"), &vTwo);
|
||||||
|
builder2.insert(state.symbols.create("nested"), &vAttrs);
|
||||||
|
|
||||||
|
Value vNested;
|
||||||
|
vNested.mkAttrs(builder2.finish());
|
||||||
|
|
||||||
|
Value vList;
|
||||||
|
state.mkList(vList, 5);
|
||||||
|
vList.bigList.elems[0] = &vOne;
|
||||||
|
vList.bigList.elems[1] = &vTwo;
|
||||||
|
vList.bigList.elems[2] = &vNested;
|
||||||
|
vList.bigList.size = 3;
|
||||||
|
|
||||||
|
test(vList, "[ «too deep» «too deep» «too deep» ]", false, 1);
|
||||||
|
test(vList, "[ 1 2 { nested = «too deep»; one = «too deep»; two = «too deep»; } ]", false, 2);
|
||||||
|
test(vList, "[ 1 2 { nested = { one = «too deep»; two = «too deep»; }; one = 1; two = 2; } ]", false, 3);
|
||||||
|
test(vList, "[ 1 2 { nested = { one = 1; two = 2; }; one = 1; two = 2; } ]", false, 4);
|
||||||
|
test(vList, "[ 1 2 { nested = { one = 1; two = 2; }; one = 1; two = 2; } ]", false, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace nix
|
|
@ -2,6 +2,7 @@
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <climits>
|
||||||
|
|
||||||
#include "symbol-table.hh"
|
#include "symbol-table.hh"
|
||||||
#include "value/context.hh"
|
#include "value/context.hh"
|
||||||
|
@ -137,11 +138,11 @@ private:
|
||||||
|
|
||||||
friend std::string showType(const Value & v);
|
friend std::string showType(const Value & v);
|
||||||
|
|
||||||
void print(const SymbolTable & symbols, std::ostream & str, std::set<const void *> * seen) const;
|
void print(const SymbolTable &symbols, std::ostream &str, std::set<const void *> *seen, int depth) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void print(const SymbolTable & symbols, std::ostream & str, bool showRepeated = false) const;
|
void print(const SymbolTable &symbols, std::ostream &str, bool showRepeated = false, int depth = INT_MAX) const;
|
||||||
|
|
||||||
// Functions needed to distinguish the type
|
// Functions needed to distinguish the type
|
||||||
// These should be removed eventually, by putting the functionality that's
|
// These should be removed eventually, by putting the functionality that's
|
||||||
|
|
Loading…
Reference in a new issue