mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-29 22:30:33 +00:00
YAML: Add an optional 'flow' field to the mapping trait to allow flow mapping output.
This patch adds an optional 'flow' field to the MappingTrait class so that yaml IO will be able to output flow mappings. Reviewers: Justin Bogner Differential Revision: http://reviews.llvm.org/D9450 llvm-svn: 236456
This commit is contained in:
parent
7ca523be5c
commit
92999a396f
@ -723,6 +723,31 @@ because it is a programming error to have invalid struct values.
|
||||
}
|
||||
};
|
||||
|
||||
Flow Mapping
|
||||
------------
|
||||
A YAML "flow mapping" is a mapping that uses the inline notation
|
||||
(e.g { x: 1, y: 0 } ) when written to YAML. To specify that a type should be
|
||||
written in YAML using flow mapping, your MappingTraits specialization should
|
||||
add "static const bool flow = true;". For instance:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
using llvm::yaml::MappingTraits;
|
||||
using llvm::yaml::IO;
|
||||
|
||||
struct Stuff {
|
||||
...
|
||||
};
|
||||
|
||||
template <>
|
||||
struct MappingTraits<Stuff> {
|
||||
static void mapping(IO &io, Stuff &stuff) {
|
||||
...
|
||||
}
|
||||
|
||||
static const bool flow = true;
|
||||
}
|
||||
|
||||
|
||||
Sequence
|
||||
========
|
||||
|
@ -46,6 +46,10 @@ struct MappingTraits {
|
||||
// static void mapping(IO &io, T &fields);
|
||||
// Optionally may provide:
|
||||
// static StringRef validate(IO &io, T &fields);
|
||||
//
|
||||
// The optional flow flag will cause generated YAML to use a flow mapping
|
||||
// (e.g. { a: 0, b: 1 }):
|
||||
// static const bool flow = true;
|
||||
};
|
||||
|
||||
|
||||
@ -445,6 +449,9 @@ public:
|
||||
virtual bool preflightKey(const char*, bool, bool, bool &, void *&) = 0;
|
||||
virtual void postflightKey(void*) = 0;
|
||||
|
||||
virtual void beginFlowMapping() = 0;
|
||||
virtual void endFlowMapping() = 0;
|
||||
|
||||
virtual void beginEnumScalar() = 0;
|
||||
virtual bool matchEnumScalar(const char*, bool) = 0;
|
||||
virtual bool matchEnumFallback() = 0;
|
||||
@ -643,7 +650,10 @@ yamlize(IO &io, T &Val, bool) {
|
||||
template<typename T>
|
||||
typename std::enable_if<validatedMappingTraits<T>::value, void>::type
|
||||
yamlize(IO &io, T &Val, bool) {
|
||||
io.beginMapping();
|
||||
if (has_FlowTraits<MappingTraits<T>>::value)
|
||||
io.beginFlowMapping();
|
||||
else
|
||||
io.beginMapping();
|
||||
if (io.outputting()) {
|
||||
StringRef Err = MappingTraits<T>::validate(io, Val);
|
||||
if (!Err.empty()) {
|
||||
@ -657,15 +667,24 @@ yamlize(IO &io, T &Val, bool) {
|
||||
if (!Err.empty())
|
||||
io.setError(Err);
|
||||
}
|
||||
io.endMapping();
|
||||
if (has_FlowTraits<MappingTraits<T>>::value)
|
||||
io.endFlowMapping();
|
||||
else
|
||||
io.endMapping();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<unvalidatedMappingTraits<T>::value, void>::type
|
||||
yamlize(IO &io, T &Val, bool) {
|
||||
io.beginMapping();
|
||||
MappingTraits<T>::mapping(io, Val);
|
||||
io.endMapping();
|
||||
if (has_FlowTraits<MappingTraits<T>>::value) {
|
||||
io.beginFlowMapping();
|
||||
MappingTraits<T>::mapping(io, Val);
|
||||
io.endFlowMapping();
|
||||
} else {
|
||||
io.beginMapping();
|
||||
MappingTraits<T>::mapping(io, Val);
|
||||
io.endMapping();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@ -900,6 +919,8 @@ private:
|
||||
void endMapping() override;
|
||||
bool preflightKey(const char *, bool, bool, bool &, void *&) override;
|
||||
void postflightKey(void *) override;
|
||||
void beginFlowMapping() override;
|
||||
void endFlowMapping() override;
|
||||
unsigned beginSequence() override;
|
||||
void endSequence() override;
|
||||
bool preflightElement(unsigned index, void *&) override;
|
||||
@ -1028,6 +1049,8 @@ public:
|
||||
void endMapping() override;
|
||||
bool preflightKey(const char *key, bool, bool, bool &, void *&) override;
|
||||
void postflightKey(void *) override;
|
||||
void beginFlowMapping() override;
|
||||
void endFlowMapping() override;
|
||||
unsigned beginSequence() override;
|
||||
void endSequence() override;
|
||||
bool preflightElement(unsigned, void *&) override;
|
||||
@ -1060,13 +1083,22 @@ private:
|
||||
void newLineCheck();
|
||||
void outputNewLine();
|
||||
void paddedKey(StringRef key);
|
||||
void flowKey(StringRef Key);
|
||||
|
||||
enum InState { inSeq, inFlowSeq, inMapFirstKey, inMapOtherKey };
|
||||
enum InState {
|
||||
inSeq,
|
||||
inFlowSeq,
|
||||
inMapFirstKey,
|
||||
inMapOtherKey,
|
||||
inFlowMapFirstKey,
|
||||
inFlowMapOtherKey
|
||||
};
|
||||
|
||||
llvm::raw_ostream &Out;
|
||||
SmallVector<InState, 8> StateStack;
|
||||
int Column;
|
||||
int ColumnAtFlowStart;
|
||||
int ColumnAtMapFlowStart;
|
||||
bool NeedBitValueComma;
|
||||
bool NeedFlowSequenceComma;
|
||||
bool EnumerationMatchFound;
|
||||
|
@ -168,6 +168,10 @@ void Input::endMapping() {
|
||||
}
|
||||
}
|
||||
|
||||
void Input::beginFlowMapping() { beginMapping(); }
|
||||
|
||||
void Input::endFlowMapping() { endMapping(); }
|
||||
|
||||
unsigned Input::beginSequence() {
|
||||
if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode))
|
||||
return SQ->Entries.size();
|
||||
@ -393,6 +397,7 @@ Output::Output(raw_ostream &yout, void *context)
|
||||
Out(yout),
|
||||
Column(0),
|
||||
ColumnAtFlowStart(0),
|
||||
ColumnAtMapFlowStart(0),
|
||||
NeedBitValueComma(false),
|
||||
NeedFlowSequenceComma(false),
|
||||
EnumerationMatchFound(false),
|
||||
@ -427,8 +432,13 @@ bool Output::preflightKey(const char *Key, bool Required, bool SameAsDefault,
|
||||
bool &UseDefault, void *&) {
|
||||
UseDefault = false;
|
||||
if (Required || !SameAsDefault) {
|
||||
this->newLineCheck();
|
||||
this->paddedKey(Key);
|
||||
auto State = StateStack.back();
|
||||
if (State == inFlowMapFirstKey || State == inFlowMapOtherKey) {
|
||||
flowKey(Key);
|
||||
} else {
|
||||
this->newLineCheck();
|
||||
this->paddedKey(Key);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -438,9 +448,24 @@ void Output::postflightKey(void *) {
|
||||
if (StateStack.back() == inMapFirstKey) {
|
||||
StateStack.pop_back();
|
||||
StateStack.push_back(inMapOtherKey);
|
||||
} else if (StateStack.back() == inFlowMapFirstKey) {
|
||||
StateStack.pop_back();
|
||||
StateStack.push_back(inFlowMapOtherKey);
|
||||
}
|
||||
}
|
||||
|
||||
void Output::beginFlowMapping() {
|
||||
StateStack.push_back(inFlowMapFirstKey);
|
||||
this->newLineCheck();
|
||||
ColumnAtMapFlowStart = Column;
|
||||
output("{ ");
|
||||
}
|
||||
|
||||
void Output::endFlowMapping() {
|
||||
StateStack.pop_back();
|
||||
this->outputUpToEndOfLine(" }");
|
||||
}
|
||||
|
||||
void Output::beginDocuments() {
|
||||
this->outputUpToEndOfLine("---");
|
||||
}
|
||||
@ -607,7 +632,9 @@ void Output::output(StringRef s) {
|
||||
|
||||
void Output::outputUpToEndOfLine(StringRef s) {
|
||||
this->output(s);
|
||||
if (StateStack.empty() || StateStack.back() != inFlowSeq)
|
||||
if (StateStack.empty() || (StateStack.back() != inFlowSeq &&
|
||||
StateStack.back() != inFlowMapFirstKey &&
|
||||
StateStack.back() != inFlowMapOtherKey))
|
||||
NeedsNewLine = true;
|
||||
}
|
||||
|
||||
@ -634,7 +661,8 @@ void Output::newLineCheck() {
|
||||
if (StateStack.back() == inSeq) {
|
||||
OutputDash = true;
|
||||
} else if ((StateStack.size() > 1) && ((StateStack.back() == inMapFirstKey) ||
|
||||
(StateStack.back() == inFlowSeq)) &&
|
||||
(StateStack.back() == inFlowSeq) ||
|
||||
(StateStack.back() == inFlowMapFirstKey)) &&
|
||||
(StateStack[StateStack.size() - 2] == inSeq)) {
|
||||
--Indent;
|
||||
OutputDash = true;
|
||||
@ -659,6 +687,20 @@ void Output::paddedKey(StringRef key) {
|
||||
output(" ");
|
||||
}
|
||||
|
||||
void Output::flowKey(StringRef Key) {
|
||||
if (StateStack.back() == inFlowMapOtherKey)
|
||||
output(", ");
|
||||
if (Column > 70) {
|
||||
output("\n");
|
||||
for (int I = 0; I < ColumnAtMapFlowStart; ++I)
|
||||
output(" ");
|
||||
Column = ColumnAtMapFlowStart;
|
||||
output(" ");
|
||||
}
|
||||
output(Key);
|
||||
output(": ");
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// traits for built-in types
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -1367,6 +1367,91 @@ TEST(YAMLIO, TestValidatingInput) {
|
||||
EXPECT_TRUE(!!yin.error());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Test flow mapping
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
struct FlowFooBar {
|
||||
int foo;
|
||||
int bar;
|
||||
|
||||
FlowFooBar() : foo(0), bar(0) {}
|
||||
FlowFooBar(int foo, int bar) : foo(foo), bar(bar) {}
|
||||
};
|
||||
|
||||
typedef std::vector<FlowFooBar> FlowFooBarSequence;
|
||||
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(FlowFooBar)
|
||||
|
||||
struct FlowFooBarDoc {
|
||||
FlowFooBar attribute;
|
||||
FlowFooBarSequence seq;
|
||||
};
|
||||
|
||||
namespace llvm {
|
||||
namespace yaml {
|
||||
template <>
|
||||
struct MappingTraits<FlowFooBar> {
|
||||
static void mapping(IO &io, FlowFooBar &fb) {
|
||||
io.mapRequired("foo", fb.foo);
|
||||
io.mapRequired("bar", fb.bar);
|
||||
}
|
||||
|
||||
static const bool flow = true;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct MappingTraits<FlowFooBarDoc> {
|
||||
static void mapping(IO &io, FlowFooBarDoc &fb) {
|
||||
io.mapRequired("attribute", fb.attribute);
|
||||
io.mapRequired("seq", fb.seq);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Test writing then reading back custom mappings
|
||||
//
|
||||
TEST(YAMLIO, TestReadWriteMyFlowMapping) {
|
||||
std::string intermediate;
|
||||
{
|
||||
FlowFooBarDoc doc;
|
||||
doc.attribute = FlowFooBar(42, 907);
|
||||
doc.seq.push_back(FlowFooBar(1, 2));
|
||||
doc.seq.push_back(FlowFooBar(0, 0));
|
||||
doc.seq.push_back(FlowFooBar(-1, 1024));
|
||||
|
||||
llvm::raw_string_ostream ostr(intermediate);
|
||||
Output yout(ostr);
|
||||
yout << doc;
|
||||
|
||||
// Verify that mappings were written in flow style
|
||||
ostr.flush();
|
||||
llvm::StringRef flowOut(intermediate);
|
||||
EXPECT_NE(llvm::StringRef::npos, flowOut.find("{ foo: 42, bar: 907 }"));
|
||||
EXPECT_NE(llvm::StringRef::npos, flowOut.find("- { foo: 1, bar: 2 }"));
|
||||
EXPECT_NE(llvm::StringRef::npos, flowOut.find("- { foo: 0, bar: 0 }"));
|
||||
EXPECT_NE(llvm::StringRef::npos, flowOut.find("- { foo: -1, bar: 1024 }"));
|
||||
}
|
||||
|
||||
{
|
||||
Input yin(intermediate);
|
||||
FlowFooBarDoc doc2;
|
||||
yin >> doc2;
|
||||
|
||||
EXPECT_FALSE(yin.error());
|
||||
EXPECT_EQ(doc2.attribute.foo, 42);
|
||||
EXPECT_EQ(doc2.attribute.bar, 907);
|
||||
EXPECT_EQ(doc2.seq.size(), 3UL);
|
||||
EXPECT_EQ(doc2.seq[0].foo, 1);
|
||||
EXPECT_EQ(doc2.seq[0].bar, 2);
|
||||
EXPECT_EQ(doc2.seq[1].foo, 0);
|
||||
EXPECT_EQ(doc2.seq[1].bar, 0);
|
||||
EXPECT_EQ(doc2.seq[2].foo, -1);
|
||||
EXPECT_EQ(doc2.seq[2].bar, 1024);
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Test error handling
|
||||
|
Loading…
Reference in New Issue
Block a user