[YAMLIO] Make line-wrapping configurable and test it.

Summary:
We would wrap flow mappings and sequences when they go over a hardcoded 70
characters limit. Make the wrapping column configurable (and default to 70
co the change should be NFC for current users). Passing 0 allows to completely
suppress the wrapping which makes it easier to handle in tools like FileCheck.

Reviewers: bogner

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D10109

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@238584 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Frederic Riss 2015-05-29 17:56:28 +00:00
parent 82fdcc0e7f
commit 9282af9d6c
4 changed files with 137 additions and 7 deletions

View File

@ -798,6 +798,8 @@ add "static const bool flow = true;". For instance:
static const bool flow = true; static const bool flow = true;
} }
Flow mappings are subject to line wrapping according to the Output object
configuration.
Sequence Sequence
======== ========
@ -845,6 +847,8 @@ With the above, if you used MyList as the data type in your native data
structures, then when converted to YAML, a flow sequence of integers structures, then when converted to YAML, a flow sequence of integers
will be used (e.g. [ 10, -3, 4 ]). will be used (e.g. [ 10, -3, 4 ]).
Flow sequences are subject to line wrapping according to the Output object
configuration.
Utility Macros Utility Macros
-------------- --------------
@ -908,14 +912,14 @@ Output
The llvm::yaml::Output class is used to generate a YAML document from your The llvm::yaml::Output class is used to generate a YAML document from your
in-memory data structures, using traits defined on your data types. in-memory data structures, using traits defined on your data types.
To instantiate an Output object you need an llvm::raw_ostream, and optionally To instantiate an Output object you need an llvm::raw_ostream, an optional
a context pointer: context pointer and an optional wrapping column:
.. code-block:: c++ .. code-block:: c++
class Output : public IO { class Output : public IO {
public: public:
Output(llvm::raw_ostream &, void *context=NULL); Output(llvm::raw_ostream &, void *context = NULL, int WrapColumn = 70);
Once you have an Output object, you can use the C++ stream operator on it Once you have an Output object, you can use the C++ stream operator on it
to write your native data as YAML. One thing to recall is that a YAML file to write your native data as YAML. One thing to recall is that a YAML file
@ -924,6 +928,10 @@ streaming as YAML is a mapping, scalar, or sequence, then Output assumes you
are generating one document and wraps the mapping output are generating one document and wraps the mapping output
with "``---``" and trailing "``...``". with "``---``" and trailing "``...``".
The WrapColumn parameter will cause the flow mappings and sequences to
line-wrap when they go over the supplied column. Pass 0 to completely
suppress the wrapping.
.. code-block:: c++ .. code-block:: c++
using llvm::yaml::Output; using llvm::yaml::Output;

View File

@ -1114,7 +1114,7 @@ private:
/// ///
class Output : public IO { class Output : public IO {
public: public:
Output(llvm::raw_ostream &, void *Ctxt=nullptr); Output(llvm::raw_ostream &, void *Ctxt = nullptr, int WrapColumn = 70);
~Output() override; ~Output() override;
bool outputting() override; bool outputting() override;
@ -1170,6 +1170,7 @@ private:
}; };
llvm::raw_ostream &Out; llvm::raw_ostream &Out;
int WrapColumn;
SmallVector<InState, 8> StateStack; SmallVector<InState, 8> StateStack;
int Column; int Column;
int ColumnAtFlowStart; int ColumnAtFlowStart;

View File

@ -404,9 +404,10 @@ bool Input::canElideEmptySequence() {
// Output // Output
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
Output::Output(raw_ostream &yout, void *context) Output::Output(raw_ostream &yout, void *context, int WrapColumn)
: IO(context), : IO(context),
Out(yout), Out(yout),
WrapColumn(WrapColumn),
Column(0), Column(0),
ColumnAtFlowStart(0), ColumnAtFlowStart(0),
ColumnAtMapFlowStart(0), ColumnAtMapFlowStart(0),
@ -529,7 +530,7 @@ void Output::endFlowSequence() {
bool Output::preflightFlowElement(unsigned, void *&) { bool Output::preflightFlowElement(unsigned, void *&) {
if (NeedFlowSequenceComma) if (NeedFlowSequenceComma)
output(", "); output(", ");
if (Column > 70) { if (WrapColumn && Column > WrapColumn) {
output("\n"); output("\n");
for (int i = 0; i < ColumnAtFlowStart; ++i) for (int i = 0; i < ColumnAtFlowStart; ++i)
output(" "); output(" ");
@ -720,7 +721,7 @@ void Output::paddedKey(StringRef key) {
void Output::flowKey(StringRef Key) { void Output::flowKey(StringRef Key) {
if (StateStack.back() == inFlowMapOtherKey) if (StateStack.back() == inFlowMapOtherKey)
output(", "); output(", ");
if (Column > 70) { if (WrapColumn && Column > WrapColumn) {
output("\n"); output("\n");
for (int I = 0; I < ColumnAtMapFlowStart; ++I) for (int I = 0; I < ColumnAtMapFlowStart; ++I)
output(" "); output(" ");

View File

@ -2074,3 +2074,123 @@ TEST(YAMLIO, TestEmptyStringSucceedsForSequence) {
EXPECT_FALSE(yin.error()); EXPECT_FALSE(yin.error());
EXPECT_TRUE(seq.empty()); EXPECT_TRUE(seq.empty());
} }
struct FlowMap {
llvm::StringRef str1, str2, str3;
FlowMap(llvm::StringRef str1, llvm::StringRef str2, llvm::StringRef str3)
: str1(str1), str2(str2), str3(str3) {}
};
namespace llvm {
namespace yaml {
template <>
struct MappingTraits<FlowMap> {
static void mapping(IO &io, FlowMap &fm) {
io.mapRequired("str1", fm.str1);
io.mapRequired("str2", fm.str2);
io.mapRequired("str3", fm.str3);
}
static const bool flow = true;
};
}
}
struct FlowSeq {
llvm::StringRef str;
FlowSeq(llvm::StringRef S) : str(S) {}
FlowSeq() = default;
};
template <>
struct ScalarTraits<FlowSeq> {
static void output(const FlowSeq &value, void*, llvm::raw_ostream &out) {
out << value.str;
}
static StringRef input(StringRef scalar, void*, FlowSeq &value) {
value.str = scalar;
return "";
}
static bool mustQuote(StringRef S) { return false; }
};
LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(FlowSeq)
TEST(YAMLIO, TestWrapFlow) {
std::string out;
llvm::raw_string_ostream ostr(out);
FlowMap Map("This is str1", "This is str2", "This is str3");
std::vector<FlowSeq> Seq;
Seq.emplace_back("This is str1");
Seq.emplace_back("This is str2");
Seq.emplace_back("This is str3");
{
// 20 is just bellow the total length of the first mapping field.
// We should wreap at every element.
Output yout(ostr, nullptr, 15);
yout << Map;
ostr.flush();
EXPECT_EQ(out,
"---\n"
"{ str1: This is str1, \n"
" str2: This is str2, \n"
" str3: This is str3 }\n"
"...\n");
out.clear();
yout << Seq;
ostr.flush();
EXPECT_EQ(out,
"---\n"
"[ This is str1, \n"
" This is str2, \n"
" This is str3 ]\n"
"...\n");
out.clear();
}
{
// 25 will allow the second field to be output on the first line.
Output yout(ostr, nullptr, 25);
yout << Map;
ostr.flush();
EXPECT_EQ(out,
"---\n"
"{ str1: This is str1, str2: This is str2, \n"
" str3: This is str3 }\n"
"...\n");
out.clear();
yout << Seq;
ostr.flush();
EXPECT_EQ(out,
"---\n"
"[ This is str1, This is str2, \n"
" This is str3 ]\n"
"...\n");
out.clear();
}
{
// 0 means no wrapping.
Output yout(ostr, nullptr, 0);
yout << Map;
ostr.flush();
EXPECT_EQ(out,
"---\n"
"{ str1: This is str1, str2: This is str2, str3: This is str3 }\n"
"...\n");
out.clear();
yout << Seq;
ostr.flush();
EXPECT_EQ(out,
"---\n"
"[ This is str1, This is str2, This is str3 ]\n"
"...\n");
out.clear();
}
}