1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-23 04:52:54 +02:00
llvm-mirror/include/llvm/Support/YAMLTraits.h
David Majnemer 4534e0a71a Object: Provide a richer means of describing auxiliary symbols
The current state of affairs has auxiliary symbols described as a big
bag of bytes. This is less than satisfying, it detracts from the YAML
file as being human readable.

Instead, allow for symbols to optionally contain their auxiliary data.
This allows us to have a much higher level way of describing things like
weak symbols, function definitions and section definitions.

This depends on D3105.

Differential Revision: http://llvm-reviews.chandlerc.com/D3092

llvm-svn: 204214
2014-03-19 04:47:47 +00:00

1182 lines
36 KiB
C++

//===- llvm/Support/YAMLTraits.h --------------------------------*- C++ -*-===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_YAMLTRAITS_H
#define LLVM_SUPPORT_YAMLTRAITS_H
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/YAMLParser.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
namespace llvm {
namespace yaml {
/// This class should be specialized by any type that needs to be converted
/// to/from a YAML mapping. For example:
///
/// struct ScalarBitSetTraits<MyStruct> {
/// static void mapping(IO &io, MyStruct &s) {
/// io.mapRequired("name", s.name);
/// io.mapRequired("size", s.size);
/// io.mapOptional("age", s.age);
/// }
/// };
template<class T>
struct MappingTraits {
// Must provide:
// static void mapping(IO &io, T &fields);
// Optionally may provide:
// static StringRef validate(IO &io, T &fields);
};
/// This class should be specialized by any integral type that converts
/// to/from a YAML scalar where there is a one-to-one mapping between
/// in-memory values and a string in YAML. For example:
///
/// struct ScalarEnumerationTraits<Colors> {
/// static void enumeration(IO &io, Colors &value) {
/// io.enumCase(value, "red", cRed);
/// io.enumCase(value, "blue", cBlue);
/// io.enumCase(value, "green", cGreen);
/// }
/// };
template<typename T>
struct ScalarEnumerationTraits {
// Must provide:
// static void enumeration(IO &io, T &value);
};
/// This class should be specialized by any integer type that is a union
/// of bit values and the YAML representation is a flow sequence of
/// strings. For example:
///
/// struct ScalarBitSetTraits<MyFlags> {
/// static void bitset(IO &io, MyFlags &value) {
/// io.bitSetCase(value, "big", flagBig);
/// io.bitSetCase(value, "flat", flagFlat);
/// io.bitSetCase(value, "round", flagRound);
/// }
/// };
template<typename T>
struct ScalarBitSetTraits {
// Must provide:
// static void bitset(IO &io, T &value);
};
/// This class should be specialized by type that requires custom conversion
/// to/from a yaml scalar. For example:
///
/// template<>
/// struct ScalarTraits<MyType> {
/// static void output(const MyType &val, void*, llvm::raw_ostream &out) {
/// // stream out custom formatting
/// out << llvm::format("%x", val);
/// }
/// static StringRef input(StringRef scalar, void*, MyType &value) {
/// // parse scalar and set `value`
/// // return empty string on success, or error string
/// return StringRef();
/// }
/// };
template<typename T>
struct ScalarTraits {
// Must provide:
//
// Function to write the value as a string:
//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);
};
/// This class should be specialized by any type that needs to be converted
/// to/from a YAML sequence. For example:
///
/// template<>
/// struct SequenceTraits< std::vector<MyType> > {
/// static size_t size(IO &io, std::vector<MyType> &seq) {
/// return seq.size();
/// }
/// static MyType& element(IO &, std::vector<MyType> &seq, size_t index) {
/// if ( index >= seq.size() )
/// seq.resize(index+1);
/// return seq[index];
/// }
/// };
template<typename T>
struct SequenceTraits {
// Must provide:
// static size_t size(IO &io, T &seq);
// static T::value_type& element(IO &io, T &seq, size_t index);
//
// The following is option and will cause generated YAML to use
// a flow sequence (e.g. [a,b,c]).
// static const bool flow = true;
};
/// This class should be specialized by any type that needs to be converted
/// to/from a list of YAML documents.
template<typename T>
struct DocumentListTraits {
// Must provide:
// static size_t size(IO &io, T &seq);
// static T::value_type& element(IO &io, T &seq, size_t index);
};
// Only used by compiler if both template types are the same
template <typename T, T>
struct SameType;
// Only used for better diagnostics of missing traits
template <typename T>
struct MissingTrait;
// Test if ScalarEnumerationTraits<T> is defined on type T.
template <class T>
struct has_ScalarEnumerationTraits
{
typedef void (*Signature_enumeration)(class IO&, T&);
template <typename U>
static char test(SameType<Signature_enumeration, &U::enumeration>*);
template <typename U>
static double test(...);
public:
static bool const value = (sizeof(test<ScalarEnumerationTraits<T> >(0)) == 1);
};
// Test if ScalarBitSetTraits<T> is defined on type T.
template <class T>
struct has_ScalarBitSetTraits
{
typedef void (*Signature_bitset)(class IO&, T&);
template <typename U>
static char test(SameType<Signature_bitset, &U::bitset>*);
template <typename U>
static double test(...);
public:
static bool const value = (sizeof(test<ScalarBitSetTraits<T> >(0)) == 1);
};
// Test if ScalarTraits<T> is defined on type T.
template <class T>
struct has_ScalarTraits
{
typedef StringRef (*Signature_input)(StringRef, void*, T&);
typedef void (*Signature_output)(const T&, void*, llvm::raw_ostream&);
template <typename U>
static char test(SameType<Signature_input, &U::input>*,
SameType<Signature_output, &U::output>*);
template <typename U>
static double test(...);
public:
static bool const value = (sizeof(test<ScalarTraits<T> >(0,0)) == 1);
};
// Test if MappingTraits<T> is defined on type T.
template <class T>
struct has_MappingTraits
{
typedef void (*Signature_mapping)(class IO&, T&);
template <typename U>
static char test(SameType<Signature_mapping, &U::mapping>*);
template <typename U>
static double test(...);
public:
static bool const value = (sizeof(test<MappingTraits<T> >(0)) == 1);
};
// Test if MappingTraits<T>::validate() is defined on type T.
template <class T>
struct has_MappingValidateTraits
{
typedef StringRef (*Signature_validate)(class IO&, T&);
template <typename U>
static char test(SameType<Signature_validate, &U::validate>*);
template <typename U>
static double test(...);
public:
static bool const value = (sizeof(test<MappingTraits<T> >(0)) == 1);
};
// Test if SequenceTraits<T> is defined on type T.
template <class T>
struct has_SequenceMethodTraits
{
typedef size_t (*Signature_size)(class IO&, T&);
template <typename U>
static char test(SameType<Signature_size, &U::size>*);
template <typename U>
static double test(...);
public:
static bool const value = (sizeof(test<SequenceTraits<T> >(0)) == 1);
};
// has_FlowTraits<int> will cause an error with some compilers because
// it subclasses int. Using this wrapper only instantiates the
// real has_FlowTraits only if the template type is a class.
template <typename T, bool Enabled = std::is_class<T>::value>
class has_FlowTraits
{
public:
static const bool value = false;
};
// Some older gcc compilers don't support straight forward tests
// for members, so test for ambiguity cause by the base and derived
// classes both defining the member.
template <class T>
struct has_FlowTraits<T, true>
{
struct Fallback { bool flow; };
struct Derived : T, Fallback { };
template<typename C>
static char (&f(SameType<bool Fallback::*, &C::flow>*))[1];
template<typename C>
static char (&f(...))[2];
public:
static bool const value = sizeof(f<Derived>(0)) == 2;
};
// Test if SequenceTraits<T> is defined on type T
template<typename T>
struct has_SequenceTraits : public std::integral_constant<bool,
has_SequenceMethodTraits<T>::value > { };
// Test if DocumentListTraits<T> is defined on type T
template <class T>
struct has_DocumentListTraits
{
typedef size_t (*Signature_size)(class IO&, T&);
template <typename U>
static char test(SameType<Signature_size, &U::size>*);
template <typename U>
static double test(...);
public:
static bool const value = (sizeof(test<DocumentListTraits<T> >(0)) == 1);
};
template<typename T>
struct missingTraits : public std::integral_constant<bool,
!has_ScalarEnumerationTraits<T>::value
&& !has_ScalarBitSetTraits<T>::value
&& !has_ScalarTraits<T>::value
&& !has_MappingTraits<T>::value
&& !has_SequenceTraits<T>::value
&& !has_DocumentListTraits<T>::value > {};
template<typename T>
struct validatedMappingTraits : public std::integral_constant<bool,
has_MappingTraits<T>::value
&& has_MappingValidateTraits<T>::value> {};
template<typename T>
struct unvalidatedMappingTraits : public std::integral_constant<bool,
has_MappingTraits<T>::value
&& !has_MappingValidateTraits<T>::value> {};
// Base class for Input and Output.
class IO {
public:
IO(void *Ctxt=NULL);
virtual ~IO();
virtual bool outputting() = 0;
virtual unsigned beginSequence() = 0;
virtual bool preflightElement(unsigned, void *&) = 0;
virtual void postflightElement(void*) = 0;
virtual void endSequence() = 0;
virtual bool canElideEmptySequence() = 0;
virtual unsigned beginFlowSequence() = 0;
virtual bool preflightFlowElement(unsigned, void *&) = 0;
virtual void postflightFlowElement(void*) = 0;
virtual void endFlowSequence() = 0;
virtual bool mapTag(StringRef Tag, bool Default=false) = 0;
virtual void beginMapping() = 0;
virtual void endMapping() = 0;
virtual bool preflightKey(const char*, bool, bool, bool &, void *&) = 0;
virtual void postflightKey(void*) = 0;
virtual void beginEnumScalar() = 0;
virtual bool matchEnumScalar(const char*, bool) = 0;
virtual void endEnumScalar() = 0;
virtual bool beginBitSetScalar(bool &) = 0;
virtual bool bitSetMatch(const char*, bool) = 0;
virtual void endBitSetScalar() = 0;
virtual void scalarString(StringRef &) = 0;
virtual void setError(const Twine &) = 0;
template <typename T>
void enumCase(T &Val, const char* Str, const T ConstVal) {
if ( matchEnumScalar(Str, outputting() && Val == ConstVal) ) {
Val = ConstVal;
}
}
// allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF
template <typename T>
void enumCase(T &Val, const char* Str, const uint32_t ConstVal) {
if ( matchEnumScalar(Str, outputting() && Val == static_cast<T>(ConstVal)) ) {
Val = ConstVal;
}
}
template <typename T>
void bitSetCase(T &Val, const char* Str, const T ConstVal) {
if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) {
Val = Val | ConstVal;
}
}
// allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF
template <typename T>
void bitSetCase(T &Val, const char* Str, const uint32_t ConstVal) {
if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) {
Val = Val | ConstVal;
}
}
void *getContext();
void setContext(void *);
template <typename T>
void mapRequired(const char* Key, T& Val) {
this->processKey(Key, Val, true);
}
template <typename T>
typename std::enable_if<has_SequenceTraits<T>::value,void>::type
mapOptional(const char* Key, T& Val) {
// omit key/value instead of outputting empty sequence
if ( this->canElideEmptySequence() && !(Val.begin() != Val.end()) )
return;
this->processKey(Key, Val, false);
}
template <typename T>
void mapOptional(const char* Key, Optional<T> &Val) {
processKeyWithDefault(Key, Val, Optional<T>(), /*Required=*/false);
}
template <typename T>
typename std::enable_if<!has_SequenceTraits<T>::value,void>::type
mapOptional(const char* Key, T& Val) {
this->processKey(Key, Val, false);
}
template <typename T>
void mapOptional(const char* Key, T& Val, const T& Default) {
this->processKeyWithDefault(Key, Val, Default, false);
}
private:
template <typename T>
void processKeyWithDefault(const char *Key, Optional<T> &Val,
const Optional<T> &DefaultValue, bool Required) {
assert(DefaultValue.hasValue() == false &&
"Optional<T> shouldn't have a value!");
void *SaveInfo;
bool UseDefault;
const bool sameAsDefault = outputting() && !Val.hasValue();
if (!outputting() && !Val.hasValue())
Val = T();
if (this->preflightKey(Key, Required, sameAsDefault, UseDefault,
SaveInfo)) {
yamlize(*this, Val.getValue(), Required);
this->postflightKey(SaveInfo);
} else {
if (UseDefault)
Val = DefaultValue;
}
}
template <typename T>
void processKeyWithDefault(const char *Key, T &Val, const T& DefaultValue,
bool Required) {
void *SaveInfo;
bool UseDefault;
const bool sameAsDefault = outputting() && Val == DefaultValue;
if ( this->preflightKey(Key, Required, sameAsDefault, UseDefault,
SaveInfo) ) {
yamlize(*this, Val, Required);
this->postflightKey(SaveInfo);
}
else {
if ( UseDefault )
Val = DefaultValue;
}
}
template <typename T>
void processKey(const char *Key, T &Val, bool Required) {
void *SaveInfo;
bool UseDefault;
if ( this->preflightKey(Key, Required, false, UseDefault, SaveInfo) ) {
yamlize(*this, Val, Required);
this->postflightKey(SaveInfo);
}
}
private:
void *Ctxt;
};
template<typename T>
typename std::enable_if<has_ScalarEnumerationTraits<T>::value,void>::type
yamlize(IO &io, T &Val, bool) {
io.beginEnumScalar();
ScalarEnumerationTraits<T>::enumeration(io, Val);
io.endEnumScalar();
}
template<typename T>
typename std::enable_if<has_ScalarBitSetTraits<T>::value,void>::type
yamlize(IO &io, T &Val, bool) {
bool DoClear;
if ( io.beginBitSetScalar(DoClear) ) {
if ( DoClear )
Val = static_cast<T>(0);
ScalarBitSetTraits<T>::bitset(io, Val);
io.endBitSetScalar();
}
}
template<typename T>
typename std::enable_if<has_ScalarTraits<T>::value,void>::type
yamlize(IO &io, T &Val, bool) {
if ( io.outputting() ) {
std::string Storage;
llvm::raw_string_ostream Buffer(Storage);
ScalarTraits<T>::output(Val, io.getContext(), Buffer);
StringRef Str = Buffer.str();
io.scalarString(Str);
}
else {
StringRef Str;
io.scalarString(Str);
StringRef Result = ScalarTraits<T>::input(Str, io.getContext(), Val);
if ( !Result.empty() ) {
io.setError(llvm::Twine(Result));
}
}
}
template<typename T>
typename std::enable_if<validatedMappingTraits<T>::value, void>::type
yamlize(IO &io, T &Val, bool) {
io.beginMapping();
if (io.outputting()) {
StringRef Err = MappingTraits<T>::validate(io, Val);
if (!Err.empty()) {
llvm::errs() << Err << "\n";
assert(Err.empty() && "invalid struct trying to be written as yaml");
}
}
MappingTraits<T>::mapping(io, Val);
if (!io.outputting()) {
StringRef Err = MappingTraits<T>::validate(io, Val);
if (!Err.empty())
io.setError(Err);
}
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();
}
template<typename T>
typename std::enable_if<missingTraits<T>::value, void>::type
yamlize(IO &io, T &Val, bool) {
char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
}
template<typename T>
typename std::enable_if<has_SequenceTraits<T>::value,void>::type
yamlize(IO &io, T &Seq, bool) {
if ( has_FlowTraits< SequenceTraits<T> >::value ) {
unsigned incnt = io.beginFlowSequence();
unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt;
for(unsigned i=0; i < count; ++i) {
void *SaveInfo;
if ( io.preflightFlowElement(i, SaveInfo) ) {
yamlize(io, SequenceTraits<T>::element(io, Seq, i), true);
io.postflightFlowElement(SaveInfo);
}
}
io.endFlowSequence();
}
else {
unsigned incnt = io.beginSequence();
unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt;
for(unsigned i=0; i < count; ++i) {
void *SaveInfo;
if ( io.preflightElement(i, SaveInfo) ) {
yamlize(io, SequenceTraits<T>::element(io, Seq, i), true);
io.postflightElement(SaveInfo);
}
}
io.endSequence();
}
}
template<>
struct ScalarTraits<bool> {
static void output(const bool &, void*, llvm::raw_ostream &);
static StringRef input(StringRef, void*, bool &);
};
template<>
struct ScalarTraits<StringRef> {
static void output(const StringRef &, void*, llvm::raw_ostream &);
static StringRef input(StringRef, void*, StringRef &);
};
template<>
struct ScalarTraits<std::string> {
static void output(const std::string &, void*, llvm::raw_ostream &);
static StringRef input(StringRef, void*, std::string &);
};
template<>
struct ScalarTraits<uint8_t> {
static void output(const uint8_t &, void*, llvm::raw_ostream &);
static StringRef input(StringRef, void*, uint8_t &);
};
template<>
struct ScalarTraits<uint16_t> {
static void output(const uint16_t &, void*, llvm::raw_ostream &);
static StringRef input(StringRef, void*, uint16_t &);
};
template<>
struct ScalarTraits<uint32_t> {
static void output(const uint32_t &, void*, llvm::raw_ostream &);
static StringRef input(StringRef, void*, uint32_t &);
};
template<>
struct ScalarTraits<uint64_t> {
static void output(const uint64_t &, void*, llvm::raw_ostream &);
static StringRef input(StringRef, void*, uint64_t &);
};
template<>
struct ScalarTraits<int8_t> {
static void output(const int8_t &, void*, llvm::raw_ostream &);
static StringRef input(StringRef, void*, int8_t &);
};
template<>
struct ScalarTraits<int16_t> {
static void output(const int16_t &, void*, llvm::raw_ostream &);
static StringRef input(StringRef, void*, int16_t &);
};
template<>
struct ScalarTraits<int32_t> {
static void output(const int32_t &, void*, llvm::raw_ostream &);
static StringRef input(StringRef, void*, int32_t &);
};
template<>
struct ScalarTraits<int64_t> {
static void output(const int64_t &, void*, llvm::raw_ostream &);
static StringRef input(StringRef, void*, int64_t &);
};
template<>
struct ScalarTraits<float> {
static void output(const float &, void*, llvm::raw_ostream &);
static StringRef input(StringRef, void*, float &);
};
template<>
struct ScalarTraits<double> {
static void output(const double &, void*, llvm::raw_ostream &);
static StringRef input(StringRef, void*, double &);
};
// Utility for use within MappingTraits<>::mapping() method
// to [de]normalize an object for use with YAML conversion.
template <typename TNorm, typename TFinal>
struct MappingNormalization {
MappingNormalization(IO &i_o, TFinal &Obj)
: io(i_o), BufPtr(NULL), Result(Obj) {
if ( io.outputting() ) {
BufPtr = new (&Buffer) TNorm(io, Obj);
}
else {
BufPtr = new (&Buffer) TNorm(io);
}
}
~MappingNormalization() {
if ( ! io.outputting() ) {
Result = BufPtr->denormalize(io);
}
BufPtr->~TNorm();
}
TNorm* operator->() { return BufPtr; }
private:
typedef llvm::AlignedCharArrayUnion<TNorm> Storage;
Storage Buffer;
IO &io;
TNorm *BufPtr;
TFinal &Result;
};
// Utility for use within MappingTraits<>::mapping() method
// to [de]normalize an object for use with YAML conversion.
template <typename TNorm, typename TFinal>
struct MappingNormalizationHeap {
MappingNormalizationHeap(IO &i_o, TFinal &Obj)
: io(i_o), BufPtr(NULL), Result(Obj) {
if ( io.outputting() ) {
BufPtr = new (&Buffer) TNorm(io, Obj);
}
else {
BufPtr = new TNorm(io);
}
}
~MappingNormalizationHeap() {
if ( io.outputting() ) {
BufPtr->~TNorm();
}
else {
Result = BufPtr->denormalize(io);
}
}
TNorm* operator->() { return BufPtr; }
private:
typedef llvm::AlignedCharArrayUnion<TNorm> Storage;
Storage Buffer;
IO &io;
TNorm *BufPtr;
TFinal &Result;
};
///
/// The Input class is used to parse a yaml document into in-memory structs
/// and vectors.
///
/// It works by using YAMLParser to do a syntax parse of the entire yaml
/// document, then the Input class builds a graph of HNodes which wraps
/// each yaml Node. The extra layer is buffering. The low level yaml
/// parser only lets you look at each node once. The buffering layer lets
/// you search and interate multiple times. This is necessary because
/// the mapRequired() method calls may not be in the same order
/// as the keys in the document.
///
class Input : public IO {
public:
// Construct a yaml Input object from a StringRef and optional
// user-data. The DiagHandler can be specified to provide
// alternative error reporting.
Input(StringRef InputContent,
void *Ctxt = NULL,
SourceMgr::DiagHandlerTy DiagHandler = NULL,
void *DiagHandlerCtxt = NULL);
~Input();
// Check if there was an syntax or semantic error during parsing.
llvm::error_code error();
private:
bool outputting() override;
bool mapTag(StringRef, bool) override;
void beginMapping() override;
void endMapping() override;
bool preflightKey(const char *, bool, bool, bool &, void *&) override;
void postflightKey(void *) override;
unsigned beginSequence() override;
void endSequence() override;
bool preflightElement(unsigned index, void *&) override;
void postflightElement(void *) override;
unsigned beginFlowSequence() override;
bool preflightFlowElement(unsigned , void *&) override;
void postflightFlowElement(void *) override;
void endFlowSequence() override;
void beginEnumScalar() override;
bool matchEnumScalar(const char*, bool) override;
void endEnumScalar() override;
bool beginBitSetScalar(bool &) override;
bool bitSetMatch(const char *, bool ) override;
void endBitSetScalar() override;
void scalarString(StringRef &) override;
void setError(const Twine &message) override;
bool canElideEmptySequence() override;
class HNode {
virtual void anchor();
public:
HNode(Node *n) : _node(n) { }
virtual ~HNode() { }
static inline bool classof(const HNode *) { return true; }
Node *_node;
};
class EmptyHNode : public HNode {
void anchor() override;
public:
EmptyHNode(Node *n) : HNode(n) { }
static inline bool classof(const HNode *n) {
return NullNode::classof(n->_node);
}
static inline bool classof(const EmptyHNode *) { return true; }
};
class ScalarHNode : public HNode {
void anchor() override;
public:
ScalarHNode(Node *n, StringRef s) : HNode(n), _value(s) { }
StringRef value() const { return _value; }
static inline bool classof(const HNode *n) {
return ScalarNode::classof(n->_node);
}
static inline bool classof(const ScalarHNode *) { return true; }
protected:
StringRef _value;
};
class MapHNode : public HNode {
public:
MapHNode(Node *n) : HNode(n) { }
virtual ~MapHNode();
static inline bool classof(const HNode *n) {
return MappingNode::classof(n->_node);
}
static inline bool classof(const MapHNode *) { return true; }
typedef llvm::StringMap<HNode*> NameToNode;
bool isValidKey(StringRef key);
NameToNode Mapping;
llvm::SmallVector<const char*, 6> ValidKeys;
};
class SequenceHNode : public HNode {
public:
SequenceHNode(Node *n) : HNode(n) { }
virtual ~SequenceHNode();
static inline bool classof(const HNode *n) {
return SequenceNode::classof(n->_node);
}
static inline bool classof(const SequenceHNode *) { return true; }
std::vector<HNode*> Entries;
};
Input::HNode *createHNodes(Node *node);
void setError(HNode *hnode, const Twine &message);
void setError(Node *node, const Twine &message);
public:
// These are only used by operator>>. They could be private
// if those templated things could be made friends.
bool setCurrentDocument();
void nextDocument();
private:
llvm::SourceMgr SrcMgr; // must be before Strm
std::unique_ptr<llvm::yaml::Stream> Strm;
std::unique_ptr<HNode> TopNode;
llvm::error_code EC;
llvm::BumpPtrAllocator StringAllocator;
llvm::yaml::document_iterator DocIterator;
std::vector<bool> BitValuesUsed;
HNode *CurrentNode;
bool ScalarMatchFound;
};
///
/// The Output class is used to generate a yaml document from in-memory structs
/// and vectors.
///
class Output : public IO {
public:
Output(llvm::raw_ostream &, void *Ctxt=NULL);
virtual ~Output();
bool outputting() override;
bool mapTag(StringRef, bool) override;
void beginMapping() override;
void endMapping() override;
bool preflightKey(const char *key, bool, bool, bool &, void *&) override;
void postflightKey(void *) override;
unsigned beginSequence() override;
void endSequence() override;
bool preflightElement(unsigned, void *&) override;
void postflightElement(void *) override;
unsigned beginFlowSequence() override;
bool preflightFlowElement(unsigned, void *&) override;
void postflightFlowElement(void *) override;
void endFlowSequence() override;
void beginEnumScalar() override;
bool matchEnumScalar(const char*, bool) override;
void endEnumScalar() override;
bool beginBitSetScalar(bool &) override;
bool bitSetMatch(const char *, bool ) override;
void endBitSetScalar() override;
void scalarString(StringRef &) override;
void setError(const Twine &message) override;
bool canElideEmptySequence() override;
public:
// These are only used by operator<<. They could be private
// if that templated operator could be made a friend.
void beginDocuments();
bool preflightDocument(unsigned);
void postflightDocument();
void endDocuments();
private:
void output(StringRef s);
void outputUpToEndOfLine(StringRef s);
void newLineCheck();
void outputNewLine();
void paddedKey(StringRef key);
enum InState { inSeq, inFlowSeq, inMapFirstKey, inMapOtherKey };
llvm::raw_ostream &Out;
SmallVector<InState, 8> StateStack;
int Column;
int ColumnAtFlowStart;
bool NeedBitValueComma;
bool NeedFlowSequenceComma;
bool EnumerationMatchFound;
bool NeedsNewLine;
};
/// YAML I/O does conversion based on types. But often native data types
/// are just a typedef of built in intergral types (e.g. int). But the C++
/// type matching system sees through the typedef and all the typedefed types
/// look like a built in type. This will cause the generic YAML I/O conversion
/// to be used. To provide better control over the YAML conversion, you can
/// use this macro instead of typedef. It will create a class with one field
/// and automatic conversion operators to and from the base type.
/// Based on BOOST_STRONG_TYPEDEF
#define LLVM_YAML_STRONG_TYPEDEF(_base, _type) \
struct _type { \
_type() { } \
_type(const _base v) : value(v) { } \
_type(const _type &v) : value(v.value) {} \
_type &operator=(const _type &rhs) { value = rhs.value; return *this; }\
_type &operator=(const _base &rhs) { value = rhs; return *this; } \
operator const _base & () const { return value; } \
bool operator==(const _type &rhs) const { return value == rhs.value; } \
bool operator==(const _base &rhs) const { return value == rhs; } \
bool operator<(const _type &rhs) const { return value < rhs.value; } \
_base value; \
};
///
/// Use these types instead of uintXX_t in any mapping to have
/// its yaml output formatted as hexadecimal.
///
LLVM_YAML_STRONG_TYPEDEF(uint8_t, Hex8)
LLVM_YAML_STRONG_TYPEDEF(uint16_t, Hex16)
LLVM_YAML_STRONG_TYPEDEF(uint32_t, Hex32)
LLVM_YAML_STRONG_TYPEDEF(uint64_t, Hex64)
template<>
struct ScalarTraits<Hex8> {
static void output(const Hex8 &, void*, llvm::raw_ostream &);
static StringRef input(StringRef, void*, Hex8 &);
};
template<>
struct ScalarTraits<Hex16> {
static void output(const Hex16 &, void*, llvm::raw_ostream &);
static StringRef input(StringRef, void*, Hex16 &);
};
template<>
struct ScalarTraits<Hex32> {
static void output(const Hex32 &, void*, llvm::raw_ostream &);
static StringRef input(StringRef, void*, Hex32 &);
};
template<>
struct ScalarTraits<Hex64> {
static void output(const Hex64 &, void*, llvm::raw_ostream &);
static StringRef input(StringRef, void*, Hex64 &);
};
// Define non-member operator>> so that Input can stream in a document list.
template <typename T>
inline
typename std::enable_if<has_DocumentListTraits<T>::value, Input &>::type
operator>>(Input &yin, T &docList) {
int i = 0;
while ( yin.setCurrentDocument() ) {
yamlize(yin, DocumentListTraits<T>::element(yin, docList, i), true);
if ( yin.error() )
return yin;
yin.nextDocument();
++i;
}
return yin;
}
// Define non-member operator>> so that Input can stream in a map as a document.
template <typename T>
inline
typename std::enable_if<has_MappingTraits<T>::value, Input &>::type
operator>>(Input &yin, T &docMap) {
yin.setCurrentDocument();
yamlize(yin, docMap, true);
return yin;
}
// Define non-member operator>> so that Input can stream in a sequence as
// a document.
template <typename T>
inline
typename std::enable_if<has_SequenceTraits<T>::value, Input &>::type
operator>>(Input &yin, T &docSeq) {
if (yin.setCurrentDocument())
yamlize(yin, docSeq, true);
return yin;
}
// Provide better error message about types missing a trait specialization
template <typename T>
inline
typename std::enable_if<missingTraits<T>::value, Input &>::type
operator>>(Input &yin, T &docSeq) {
char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
return yin;
}
// Define non-member operator<< so that Output can stream out document list.
template <typename T>
inline
typename std::enable_if<has_DocumentListTraits<T>::value, Output &>::type
operator<<(Output &yout, T &docList) {
yout.beginDocuments();
const size_t count = DocumentListTraits<T>::size(yout, docList);
for(size_t i=0; i < count; ++i) {
if ( yout.preflightDocument(i) ) {
yamlize(yout, DocumentListTraits<T>::element(yout, docList, i), true);
yout.postflightDocument();
}
}
yout.endDocuments();
return yout;
}
// Define non-member operator<< so that Output can stream out a map.
template <typename T>
inline
typename std::enable_if<has_MappingTraits<T>::value, Output &>::type
operator<<(Output &yout, T &map) {
yout.beginDocuments();
if ( yout.preflightDocument(0) ) {
yamlize(yout, map, true);
yout.postflightDocument();
}
yout.endDocuments();
return yout;
}
// Define non-member operator<< so that Output can stream out a sequence.
template <typename T>
inline
typename std::enable_if<has_SequenceTraits<T>::value, Output &>::type
operator<<(Output &yout, T &seq) {
yout.beginDocuments();
if ( yout.preflightDocument(0) ) {
yamlize(yout, seq, true);
yout.postflightDocument();
}
yout.endDocuments();
return yout;
}
// Provide better error message about types missing a trait specialization
template <typename T>
inline
typename std::enable_if<missingTraits<T>::value, Output &>::type
operator<<(Output &yout, T &seq) {
char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
return yout;
}
} // namespace yaml
} // namespace llvm
/// Utility for declaring that a std::vector of a particular type
/// should be considered a YAML sequence.
#define LLVM_YAML_IS_SEQUENCE_VECTOR(_type) \
namespace llvm { \
namespace yaml { \
template<> \
struct SequenceTraits< std::vector<_type> > { \
static size_t size(IO &io, std::vector<_type> &seq) { \
return seq.size(); \
} \
static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\
if ( index >= seq.size() ) \
seq.resize(index+1); \
return seq[index]; \
} \
}; \
} \
}
/// Utility for declaring that a std::vector of a particular type
/// should be considered a YAML flow sequence.
#define LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(_type) \
namespace llvm { \
namespace yaml { \
template<> \
struct SequenceTraits< std::vector<_type> > { \
static size_t size(IO &io, std::vector<_type> &seq) { \
return seq.size(); \
} \
static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\
(void)flow; /* Remove this workaround after PR17897 is fixed */ \
if ( index >= seq.size() ) \
seq.resize(index+1); \
return seq[index]; \
} \
static const bool flow = true; \
}; \
} \
}
/// Utility for declaring that a std::vector of a particular type
/// should be considered a YAML document list.
#define LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(_type) \
namespace llvm { \
namespace yaml { \
template<> \
struct DocumentListTraits< std::vector<_type> > { \
static size_t size(IO &io, std::vector<_type> &seq) { \
return seq.size(); \
} \
static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\
if ( index >= seq.size() ) \
seq.resize(index+1); \
return seq[index]; \
} \
}; \
} \
}
#endif // LLVM_SUPPORT_YAMLTRAITS_H