summaryrefslogtreecommitdiffstats
path: root/llvm/include
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/include')
-rw-r--r--llvm/include/llvm/Support/YAMLTraits.h198
1 files changed, 191 insertions, 7 deletions
diff --git a/llvm/include/llvm/Support/YAMLTraits.h b/llvm/include/llvm/Support/YAMLTraits.h
index 6219755e83a..3d790e96fff 100644
--- a/llvm/include/llvm/Support/YAMLTraits.h
+++ b/llvm/include/llvm/Support/YAMLTraits.h
@@ -39,6 +39,12 @@
namespace llvm {
namespace yaml {
+enum class NodeKind : uint8_t {
+ Scalar,
+ Map,
+ Sequence,
+};
+
struct EmptyContext {};
/// This class should be specialized by any type that needs to be converted
@@ -145,14 +151,14 @@ struct ScalarTraits {
// Must provide:
//
// Function to write the value as a string:
- //static void output(const T &value, void *ctxt, llvm::raw_ostream &out);
+ // static void output(const T &value, void *ctxt, llvm::raw_ostream &out);
//
// Function to convert a string to a value. Returns the empty
// StringRef on success or an error string if string is malformed:
- //static StringRef input(StringRef scalar, void *ctxt, T &value);
+ // static StringRef input(StringRef scalar, void *ctxt, T &value);
//
// Function to determine if the value should be quoted.
- //static QuotingType mustQuote(StringRef);
+ // static QuotingType mustQuote(StringRef);
};
/// This class should be specialized by type that requires custom conversion
@@ -163,7 +169,7 @@ struct ScalarTraits {
/// static void output(const MyType &Value, void*, llvm::raw_ostream &Out)
/// {
/// // stream out custom formatting
-/// Out << Val;
+/// Out << Value;
/// }
/// static StringRef input(StringRef Scalar, void*, MyType &Value) {
/// // parse scalar and set `value`
@@ -181,6 +187,47 @@ struct BlockScalarTraits {
// Function to convert a string to a value. Returns the empty
// StringRef on success or an error string if string is malformed:
// static StringRef input(StringRef Scalar, void *ctxt, T &Value);
+ //
+ // Optional:
+ // static StringRef inputTag(T &Val, std::string Tag)
+ // static void outputTag(const T &Val, raw_ostream &Out)
+};
+
+/// This class should be specialized by type that requires custom conversion
+/// to/from a YAML scalar with optional tags. For example:
+///
+/// template <>
+/// struct TaggedScalarTraits<MyType> {
+/// static void output(const MyType &Value, void*, llvm::raw_ostream
+/// &ScalarOut, llvm::raw_ostream &TagOut)
+/// {
+/// // stream out custom formatting including optional Tag
+/// Out << Value;
+/// }
+/// static StringRef input(StringRef Scalar, StringRef Tag, void*, MyType
+/// &Value) {
+/// // parse scalar and set `value`
+/// // return empty string on success, or error string
+/// return StringRef();
+/// }
+/// static QuotingType mustQuote(const MyType &Value, StringRef) {
+/// return QuotingType::Single;
+/// }
+/// };
+template <typename T> struct TaggedScalarTraits {
+ // Must provide:
+ //
+ // Function to write the value and tag as strings:
+ // static void output(const T &Value, void *ctx, llvm::raw_ostream &ScalarOut,
+ // llvm::raw_ostream &TagOut);
+ //
+ // Function to convert a string to a value. Returns the empty
+ // StringRef on success or an error string if string is malformed:
+ // static StringRef input(StringRef Scalar, StringRef Tag, void *ctxt, T
+ // &Value);
+ //
+ // Function to determine if the value should be quoted.
+ // static QuotingType mustQuote(const T &Value, StringRef Scalar);
};
/// This class should be specialized by any type that needs to be converted
@@ -234,6 +281,31 @@ struct CustomMappingTraits {
// static void output(IO &io, T &elem);
};
+/// This class should be specialized by any type that can be represented as
+/// a scalar, map, or sequence, decided dynamically. For example:
+///
+/// typedef std::unique_ptr<MyBase> MyPoly;
+///
+/// template<>
+/// struct PolymorphicTraits<MyPoly> {
+/// static NodeKind getKind(const MyPoly &poly) {
+/// return poly->getKind();
+/// }
+/// static MyScalar& getAsScalar(MyPoly &poly) {
+/// if (!poly || !isa<MyScalar>(poly))
+/// poly.reset(new MyScalar());
+/// return *cast<MyScalar>(poly.get());
+/// }
+/// // ...
+/// };
+template <typename T> struct PolymorphicTraits {
+ // Must provide:
+ // static NodeKind getKind(const T &poly);
+ // static scalar_type &getAsScalar(T &poly);
+ // static map_type &getAsMap(T &poly);
+ // static sequence_type &getAsSequence(T &poly);
+};
+
// Only used for better diagnostics of missing traits
template <typename T>
struct MissingTrait;
@@ -307,6 +379,24 @@ struct has_BlockScalarTraits
(sizeof(test<BlockScalarTraits<T>>(nullptr, nullptr)) == 1);
};
+// Test if TaggedScalarTraits<T> is defined on type T.
+template <class T> struct has_TaggedScalarTraits {
+ using Signature_input = StringRef (*)(StringRef, StringRef, void *, T &);
+ using Signature_output = void (*)(const T &, void *, raw_ostream &,
+ raw_ostream &);
+ using Signature_mustQuote = QuotingType (*)(const T &, StringRef);
+
+ template <typename U>
+ static char test(SameType<Signature_input, &U::input> *,
+ SameType<Signature_output, &U::output> *,
+ SameType<Signature_mustQuote, &U::mustQuote> *);
+
+ template <typename U> static double test(...);
+
+ static bool const value =
+ (sizeof(test<TaggedScalarTraits<T>>(nullptr, nullptr, nullptr)) == 1);
+};
+
// Test if MappingContextTraits<T> is defined on type T.
template <class T, class Context> struct has_MappingTraits {
using Signature_mapping = void (*)(class IO &, T &, Context &);
@@ -438,6 +528,17 @@ struct has_DocumentListTraits
static bool const value = (sizeof(test<DocumentListTraits<T>>(nullptr))==1);
};
+template <class T> struct has_PolymorphicTraits {
+ using Signature_getKind = NodeKind (*)(const T &);
+
+ template <typename U>
+ static char test(SameType<Signature_getKind, &U::getKind> *);
+
+ template <typename U> static double test(...);
+
+ static bool const value = (sizeof(test<PolymorphicTraits<T>>(nullptr)) == 1);
+};
+
inline bool isNumeric(StringRef S) {
const static auto skipDigits = [](StringRef Input) {
return Input.drop_front(
@@ -626,10 +727,12 @@ struct missingTraits
!has_ScalarBitSetTraits<T>::value &&
!has_ScalarTraits<T>::value &&
!has_BlockScalarTraits<T>::value &&
+ !has_TaggedScalarTraits<T>::value &&
!has_MappingTraits<T, Context>::value &&
!has_SequenceTraits<T>::value &&
!has_CustomMappingTraits<T>::value &&
- !has_DocumentListTraits<T>::value> {};
+ !has_DocumentListTraits<T>::value &&
+ !has_PolymorphicTraits<T>::value> {};
template <typename T, typename Context>
struct validatedMappingTraits
@@ -683,6 +786,9 @@ public:
virtual void scalarString(StringRef &, QuotingType) = 0;
virtual void blockScalarString(StringRef &) = 0;
+ virtual void scalarTag(std::string &) = 0;
+
+ virtual NodeKind getNodeKind() = 0;
virtual void setError(const Twine &) = 0;
@@ -917,6 +1023,31 @@ yamlize(IO &YamlIO, T &Val, bool, EmptyContext &Ctx) {
}
}
+template <typename T>
+typename std::enable_if<has_TaggedScalarTraits<T>::value, void>::type
+yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
+ if (io.outputting()) {
+ std::string ScalarStorage, TagStorage;
+ raw_string_ostream ScalarBuffer(ScalarStorage), TagBuffer(TagStorage);
+ TaggedScalarTraits<T>::output(Val, io.getContext(), ScalarBuffer,
+ TagBuffer);
+ io.scalarTag(TagBuffer.str());
+ StringRef ScalarStr = ScalarBuffer.str();
+ io.scalarString(ScalarStr,
+ TaggedScalarTraits<T>::mustQuote(Val, ScalarStr));
+ } else {
+ std::string Tag;
+ io.scalarTag(Tag);
+ StringRef Str;
+ io.scalarString(Str, QuotingType::None);
+ StringRef Result =
+ TaggedScalarTraits<T>::input(Str, Tag, io.getContext(), Val);
+ if (!Result.empty()) {
+ io.setError(Twine(Result));
+ }
+ }
+}
+
template <typename T, typename Context>
typename std::enable_if<validatedMappingTraits<T, Context>::value, void>::type
yamlize(IO &io, T &Val, bool, Context &Ctx) {
@@ -973,6 +1104,20 @@ yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
}
template <typename T>
+typename std::enable_if<has_PolymorphicTraits<T>::value, void>::type
+yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
+ switch (io.outputting() ? PolymorphicTraits<T>::getKind(Val)
+ : io.getNodeKind()) {
+ case NodeKind::Scalar:
+ return yamlize(io, PolymorphicTraits<T>::getAsScalar(Val), true, Ctx);
+ case NodeKind::Map:
+ return yamlize(io, PolymorphicTraits<T>::getAsMap(Val), true, Ctx);
+ case NodeKind::Sequence:
+ return yamlize(io, PolymorphicTraits<T>::getAsSequence(Val), true, Ctx);
+ }
+}
+
+template <typename T>
typename std::enable_if<missingTraits<T, EmptyContext>::value, void>::type
yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
@@ -1250,6 +1395,8 @@ private:
void endBitSetScalar() override;
void scalarString(StringRef &, QuotingType) override;
void blockScalarString(StringRef &) override;
+ void scalarTag(std::string &) override;
+ NodeKind getNodeKind() override;
void setError(const Twine &message) override;
bool canElideEmptySequence() override;
@@ -1395,6 +1542,8 @@ public:
void endBitSetScalar() override;
void scalarString(StringRef &, QuotingType) override;
void blockScalarString(StringRef &) override;
+ void scalarTag(std::string &) override;
+ NodeKind getNodeKind() override;
void setError(const Twine &message) override;
bool canElideEmptySequence() override;
@@ -1414,14 +1563,21 @@ private:
void flowKey(StringRef Key);
enum InState {
- inSeq,
- inFlowSeq,
+ inSeqFirstElement,
+ inSeqOtherElement,
+ inFlowSeqFirstElement,
+ inFlowSeqOtherElement,
inMapFirstKey,
inMapOtherKey,
inFlowMapFirstKey,
inFlowMapOtherKey
};
+ static bool inSeqAnyElement(InState State);
+ static bool inFlowSeqAnyElement(InState State);
+ static bool inMapAnyKey(InState State);
+ static bool inFlowMapAnyKey(InState State);
+
raw_ostream &Out;
int WrapColumn;
SmallVector<InState, 8> StateStack;
@@ -1557,6 +1713,16 @@ operator>>(Input &In, T &Val) {
return In;
}
+// Define non-member operator>> so that Input can stream in a polymorphic type.
+template <typename T>
+inline typename std::enable_if<has_PolymorphicTraits<T>::value, Input &>::type
+operator>>(Input &In, T &Val) {
+ EmptyContext Ctx;
+ if (In.setCurrentDocument())
+ yamlize(In, Val, true, Ctx);
+ return In;
+}
+
// Provide better error message about types missing a trait specialization
template <typename T>
inline typename std::enable_if<missingTraits<T, EmptyContext>::value,
@@ -1645,6 +1811,24 @@ operator<<(Output &Out, T &Val) {
return Out;
}
+// Define non-member operator<< so that Output can stream out a polymorphic
+// type.
+template <typename T>
+inline typename std::enable_if<has_PolymorphicTraits<T>::value, Output &>::type
+operator<<(Output &Out, T &Val) {
+ EmptyContext Ctx;
+ Out.beginDocuments();
+ if (Out.preflightDocument(0)) {
+ // FIXME: The parser does not support explicit documents terminated with a
+ // plain scalar; the end-marker is included as part of the scalar token.
+ assert(PolymorphicTraits<T>::getKind(Val) != NodeKind::Scalar && "plain scalar documents are not supported");
+ yamlize(Out, Val, true, Ctx);
+ Out.postflightDocument();
+ }
+ Out.endDocuments();
+ return Out;
+}
+
// Provide better error message about types missing a trait specialization
template <typename T>
inline typename std::enable_if<missingTraits<T, EmptyContext>::value,
OpenPOWER on IntegriCloud