YAMLTraits.h revision 263508
1//===- llvm/Supporrt/YAMLTraits.h -------------------------------*- C++ -*-===//
2//
3//                             The LLVM Linker
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef LLVM_SUPPORT_YAMLTRAITS_H
11#define LLVM_SUPPORT_YAMLTRAITS_H
12
13
14#include "llvm/ADT/DenseMap.h"
15#include "llvm/ADT/DenseMapInfo.h"
16#include "llvm/ADT/SmallVector.h"
17#include "llvm/ADT/StringMap.h"
18#include "llvm/ADT/StringRef.h"
19#include "llvm/ADT/StringSwitch.h"
20#include "llvm/ADT/Twine.h"
21#include "llvm/Support/Casting.h"
22#include "llvm/Support/Compiler.h"
23#include "llvm/Support/SourceMgr.h"
24#include "llvm/Support/YAMLParser.h"
25#include "llvm/Support/raw_ostream.h"
26#include "llvm/Support/system_error.h"
27#include "llvm/Support/type_traits.h"
28
29
30namespace llvm {
31namespace yaml {
32
33
34/// This class should be specialized by any type that needs to be converted
35/// to/from a YAML mapping.  For example:
36///
37///     struct ScalarBitSetTraits<MyStruct> {
38///       static void mapping(IO &io, MyStruct &s) {
39///         io.mapRequired("name", s.name);
40///         io.mapRequired("size", s.size);
41///         io.mapOptional("age",  s.age);
42///       }
43///     };
44template<class T>
45struct MappingTraits {
46  // Must provide:
47  // static void mapping(IO &io, T &fields);
48};
49
50
51/// This class should be specialized by any integral type that converts
52/// to/from a YAML scalar where there is a one-to-one mapping between
53/// in-memory values and a string in YAML.  For example:
54///
55///     struct ScalarEnumerationTraits<Colors> {
56///         static void enumeration(IO &io, Colors &value) {
57///           io.enumCase(value, "red",   cRed);
58///           io.enumCase(value, "blue",  cBlue);
59///           io.enumCase(value, "green", cGreen);
60///         }
61///       };
62template<typename T>
63struct ScalarEnumerationTraits {
64  // Must provide:
65  // static void enumeration(IO &io, T &value);
66};
67
68
69/// This class should be specialized by any integer type that is a union
70/// of bit values and the YAML representation is a flow sequence of
71/// strings.  For example:
72///
73///      struct ScalarBitSetTraits<MyFlags> {
74///        static void bitset(IO &io, MyFlags &value) {
75///          io.bitSetCase(value, "big",   flagBig);
76///          io.bitSetCase(value, "flat",  flagFlat);
77///          io.bitSetCase(value, "round", flagRound);
78///        }
79///      };
80template<typename T>
81struct ScalarBitSetTraits {
82  // Must provide:
83  // static void bitset(IO &io, T &value);
84};
85
86
87/// This class should be specialized by type that requires custom conversion
88/// to/from a yaml scalar.  For example:
89///
90///    template<>
91///    struct ScalarTraits<MyType> {
92///      static void output(const MyType &val, void*, llvm::raw_ostream &out) {
93///        // stream out custom formatting
94///        out << llvm::format("%x", val);
95///      }
96///      static StringRef input(StringRef scalar, void*, MyType &value) {
97///        // parse scalar and set `value`
98///        // return empty string on success, or error string
99///        return StringRef();
100///      }
101///    };
102template<typename T>
103struct ScalarTraits {
104  // Must provide:
105  //
106  // Function to write the value as a string:
107  //static void output(const T &value, void *ctxt, llvm::raw_ostream &out);
108  //
109  // Function to convert a string to a value.  Returns the empty
110  // StringRef on success or an error string if string is malformed:
111  //static StringRef input(StringRef scalar, void *ctxt, T &value);
112};
113
114
115/// This class should be specialized by any type that needs to be converted
116/// to/from a YAML sequence.  For example:
117///
118///    template<>
119///    struct SequenceTraits< std::vector<MyType> > {
120///      static size_t size(IO &io, std::vector<MyType> &seq) {
121///        return seq.size();
122///      }
123///      static MyType& element(IO &, std::vector<MyType> &seq, size_t index) {
124///        if ( index >= seq.size() )
125///          seq.resize(index+1);
126///        return seq[index];
127///      }
128///    };
129template<typename T>
130struct SequenceTraits {
131  // Must provide:
132  // static size_t size(IO &io, T &seq);
133  // static T::value_type& element(IO &io, T &seq, size_t index);
134  //
135  // The following is option and will cause generated YAML to use
136  // a flow sequence (e.g. [a,b,c]).
137  // static const bool flow = true;
138};
139
140
141/// This class should be specialized by any type that needs to be converted
142/// to/from a list of YAML documents.
143template<typename T>
144struct DocumentListTraits {
145  // Must provide:
146  // static size_t size(IO &io, T &seq);
147  // static T::value_type& element(IO &io, T &seq, size_t index);
148};
149
150
151// Only used by compiler if both template types are the same
152template <typename T, T>
153struct SameType;
154
155// Only used for better diagnostics of missing traits
156template <typename T>
157struct MissingTrait;
158
159
160
161// Test if ScalarEnumerationTraits<T> is defined on type T.
162template <class T>
163struct has_ScalarEnumerationTraits
164{
165  typedef void (*Signature_enumeration)(class IO&, T&);
166
167  template <typename U>
168  static char test(SameType<Signature_enumeration, &U::enumeration>*);
169
170  template <typename U>
171  static double test(...);
172
173public:
174  static bool const value = (sizeof(test<ScalarEnumerationTraits<T> >(0)) == 1);
175};
176
177
178// Test if ScalarBitSetTraits<T> is defined on type T.
179template <class T>
180struct has_ScalarBitSetTraits
181{
182  typedef void (*Signature_bitset)(class IO&, T&);
183
184  template <typename U>
185  static char test(SameType<Signature_bitset, &U::bitset>*);
186
187  template <typename U>
188  static double test(...);
189
190public:
191  static bool const value = (sizeof(test<ScalarBitSetTraits<T> >(0)) == 1);
192};
193
194
195// Test if ScalarTraits<T> is defined on type T.
196template <class T>
197struct has_ScalarTraits
198{
199  typedef StringRef (*Signature_input)(StringRef, void*, T&);
200  typedef void (*Signature_output)(const T&, void*, llvm::raw_ostream&);
201
202  template <typename U>
203  static char test(SameType<Signature_input, &U::input>*,
204                   SameType<Signature_output, &U::output>*);
205
206  template <typename U>
207  static double test(...);
208
209public:
210  static bool const value = (sizeof(test<ScalarTraits<T> >(0,0)) == 1);
211};
212
213
214// Test if MappingTraits<T> is defined on type T.
215template <class T>
216struct has_MappingTraits
217{
218  typedef void (*Signature_mapping)(class IO&, T&);
219
220  template <typename U>
221  static char test(SameType<Signature_mapping, &U::mapping>*);
222
223  template <typename U>
224  static double test(...);
225
226public:
227  static bool const value = (sizeof(test<MappingTraits<T> >(0)) == 1);
228};
229
230
231// Test if SequenceTraits<T> is defined on type T.
232template <class T>
233struct has_SequenceMethodTraits
234{
235  typedef size_t (*Signature_size)(class IO&, T&);
236
237  template <typename U>
238  static char test(SameType<Signature_size, &U::size>*);
239
240  template <typename U>
241  static double test(...);
242
243public:
244  static bool const value =  (sizeof(test<SequenceTraits<T> >(0)) == 1);
245};
246
247
248// has_FlowTraits<int> will cause an error with some compilers because
249// it subclasses int.  Using this wrapper only instantiates the
250// real has_FlowTraits only if the template type is a class.
251template <typename T, bool Enabled = llvm::is_class<T>::value>
252class has_FlowTraits
253{
254public:
255   static const bool value = false;
256};
257
258// Some older gcc compilers don't support straight forward tests
259// for members, so test for ambiguity cause by the base and derived
260// classes both defining the member.
261template <class T>
262struct has_FlowTraits<T, true>
263{
264  struct Fallback { bool flow; };
265  struct Derived : T, Fallback { };
266
267  template<typename C>
268  static char (&f(SameType<bool Fallback::*, &C::flow>*))[1];
269
270  template<typename C>
271  static char (&f(...))[2];
272
273public:
274  static bool const value = sizeof(f<Derived>(0)) == 2;
275};
276
277
278
279// Test if SequenceTraits<T> is defined on type T
280template<typename T>
281struct has_SequenceTraits : public  llvm::integral_constant<bool,
282                                      has_SequenceMethodTraits<T>::value > { };
283
284
285// Test if DocumentListTraits<T> is defined on type T
286template <class T>
287struct has_DocumentListTraits
288{
289  typedef size_t (*Signature_size)(class IO&, T&);
290
291  template <typename U>
292  static char test(SameType<Signature_size, &U::size>*);
293
294  template <typename U>
295  static double test(...);
296
297public:
298  static bool const value =  (sizeof(test<DocumentListTraits<T> >(0)) == 1);
299};
300
301
302
303
304template<typename T>
305struct missingTraits : public  llvm::integral_constant<bool,
306                                         !has_ScalarEnumerationTraits<T>::value
307                                      && !has_ScalarBitSetTraits<T>::value
308                                      && !has_ScalarTraits<T>::value
309                                      && !has_MappingTraits<T>::value
310                                      && !has_SequenceTraits<T>::value
311                                      && !has_DocumentListTraits<T>::value >  {};
312
313
314// Base class for Input and Output.
315class IO {
316public:
317
318  IO(void *Ctxt=NULL);
319  virtual ~IO();
320
321  virtual bool outputting() const = 0;
322
323  virtual unsigned beginSequence() = 0;
324  virtual bool preflightElement(unsigned, void *&) = 0;
325  virtual void postflightElement(void*) = 0;
326  virtual void endSequence() = 0;
327  virtual bool canElideEmptySequence() = 0;
328
329  virtual unsigned beginFlowSequence() = 0;
330  virtual bool preflightFlowElement(unsigned, void *&) = 0;
331  virtual void postflightFlowElement(void*) = 0;
332  virtual void endFlowSequence() = 0;
333
334  virtual bool mapTag(StringRef Tag, bool Default=false) = 0;
335  virtual void beginMapping() = 0;
336  virtual void endMapping() = 0;
337  virtual bool preflightKey(const char*, bool, bool, bool &, void *&) = 0;
338  virtual void postflightKey(void*) = 0;
339
340  virtual void beginEnumScalar() = 0;
341  virtual bool matchEnumScalar(const char*, bool) = 0;
342  virtual void endEnumScalar() = 0;
343
344  virtual bool beginBitSetScalar(bool &) = 0;
345  virtual bool bitSetMatch(const char*, bool) = 0;
346  virtual void endBitSetScalar() = 0;
347
348  virtual void scalarString(StringRef &) = 0;
349
350  virtual void setError(const Twine &) = 0;
351
352  template <typename T>
353  void enumCase(T &Val, const char* Str, const T ConstVal) {
354    if ( matchEnumScalar(Str, outputting() && Val == ConstVal) ) {
355      Val = ConstVal;
356    }
357  }
358
359  // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF
360  template <typename T>
361  void enumCase(T &Val, const char* Str, const uint32_t ConstVal) {
362    if ( matchEnumScalar(Str, outputting() && Val == static_cast<T>(ConstVal)) ) {
363      Val = ConstVal;
364    }
365  }
366
367  template <typename T>
368  void bitSetCase(T &Val, const char* Str, const T ConstVal) {
369    if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) {
370      Val = Val | ConstVal;
371    }
372  }
373
374  // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF
375  template <typename T>
376  void bitSetCase(T &Val, const char* Str, const uint32_t ConstVal) {
377    if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) {
378      Val = Val | ConstVal;
379    }
380  }
381
382  void *getContext();
383  void setContext(void *);
384
385  template <typename T>
386  void mapRequired(const char* Key, T& Val) {
387    this->processKey(Key, Val, true);
388  }
389
390  template <typename T>
391  typename llvm::enable_if_c<has_SequenceTraits<T>::value,void>::type
392  mapOptional(const char* Key, T& Val) {
393    // omit key/value instead of outputting empty sequence
394    if ( this->canElideEmptySequence() && !(Val.begin() != Val.end()) )
395      return;
396    this->processKey(Key, Val, false);
397  }
398
399  template <typename T>
400  typename llvm::enable_if_c<!has_SequenceTraits<T>::value,void>::type
401  mapOptional(const char* Key, T& Val) {
402    this->processKey(Key, Val, false);
403  }
404
405  template <typename T>
406  void mapOptional(const char* Key, T& Val, const T& Default) {
407    this->processKeyWithDefault(Key, Val, Default, false);
408  }
409
410private:
411  template <typename T>
412  void processKeyWithDefault(const char *Key, T &Val, const T& DefaultValue,
413                                                                bool Required) {
414    void *SaveInfo;
415    bool UseDefault;
416    const bool sameAsDefault = outputting() && Val == DefaultValue;
417    if ( this->preflightKey(Key, Required, sameAsDefault, UseDefault,
418                                                                  SaveInfo) ) {
419      yamlize(*this, Val, Required);
420      this->postflightKey(SaveInfo);
421    }
422    else {
423      if ( UseDefault )
424        Val = DefaultValue;
425    }
426  }
427
428  template <typename T>
429  void processKey(const char *Key, T &Val, bool Required) {
430    void *SaveInfo;
431    bool UseDefault;
432    if ( this->preflightKey(Key, Required, false, UseDefault, SaveInfo) ) {
433      yamlize(*this, Val, Required);
434      this->postflightKey(SaveInfo);
435    }
436  }
437
438private:
439  void  *Ctxt;
440};
441
442
443
444template<typename T>
445typename llvm::enable_if_c<has_ScalarEnumerationTraits<T>::value,void>::type
446yamlize(IO &io, T &Val, bool) {
447  io.beginEnumScalar();
448  ScalarEnumerationTraits<T>::enumeration(io, Val);
449  io.endEnumScalar();
450}
451
452template<typename T>
453typename llvm::enable_if_c<has_ScalarBitSetTraits<T>::value,void>::type
454yamlize(IO &io, T &Val, bool) {
455  bool DoClear;
456  if ( io.beginBitSetScalar(DoClear) ) {
457    if ( DoClear )
458      Val = static_cast<T>(0);
459    ScalarBitSetTraits<T>::bitset(io, Val);
460    io.endBitSetScalar();
461  }
462}
463
464
465template<typename T>
466typename llvm::enable_if_c<has_ScalarTraits<T>::value,void>::type
467yamlize(IO &io, T &Val, bool) {
468  if ( io.outputting() ) {
469    std::string Storage;
470    llvm::raw_string_ostream Buffer(Storage);
471    ScalarTraits<T>::output(Val, io.getContext(), Buffer);
472    StringRef Str = Buffer.str();
473    io.scalarString(Str);
474  }
475  else {
476    StringRef Str;
477    io.scalarString(Str);
478    StringRef Result = ScalarTraits<T>::input(Str, io.getContext(), Val);
479    if ( !Result.empty() ) {
480      io.setError(llvm::Twine(Result));
481    }
482  }
483}
484
485
486template<typename T>
487typename llvm::enable_if_c<has_MappingTraits<T>::value, void>::type
488yamlize(IO &io, T &Val, bool) {
489  io.beginMapping();
490  MappingTraits<T>::mapping(io, Val);
491  io.endMapping();
492}
493
494template<typename T>
495typename llvm::enable_if_c<missingTraits<T>::value, void>::type
496yamlize(IO &io, T &Val, bool) {
497  char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
498}
499
500template<typename T>
501typename llvm::enable_if_c<has_SequenceTraits<T>::value,void>::type
502yamlize(IO &io, T &Seq, bool) {
503  if ( has_FlowTraits< SequenceTraits<T> >::value ) {
504    unsigned incnt = io.beginFlowSequence();
505    unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt;
506    for(unsigned i=0; i < count; ++i) {
507      void *SaveInfo;
508      if ( io.preflightFlowElement(i, SaveInfo) ) {
509        yamlize(io, SequenceTraits<T>::element(io, Seq, i), true);
510        io.postflightFlowElement(SaveInfo);
511      }
512    }
513    io.endFlowSequence();
514  }
515  else {
516    unsigned incnt = io.beginSequence();
517    unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt;
518    for(unsigned i=0; i < count; ++i) {
519      void *SaveInfo;
520      if ( io.preflightElement(i, SaveInfo) ) {
521        yamlize(io, SequenceTraits<T>::element(io, Seq, i), true);
522        io.postflightElement(SaveInfo);
523      }
524    }
525    io.endSequence();
526  }
527}
528
529
530template<>
531struct ScalarTraits<bool> {
532  static void output(const bool &, void*, llvm::raw_ostream &);
533  static StringRef input(StringRef, void*, bool &);
534};
535
536template<>
537struct ScalarTraits<StringRef> {
538  static void output(const StringRef &, void*, llvm::raw_ostream &);
539  static StringRef input(StringRef, void*, StringRef &);
540};
541
542template<>
543struct ScalarTraits<uint8_t> {
544  static void output(const uint8_t &, void*, llvm::raw_ostream &);
545  static StringRef input(StringRef, void*, uint8_t &);
546};
547
548template<>
549struct ScalarTraits<uint16_t> {
550  static void output(const uint16_t &, void*, llvm::raw_ostream &);
551  static StringRef input(StringRef, void*, uint16_t &);
552};
553
554template<>
555struct ScalarTraits<uint32_t> {
556  static void output(const uint32_t &, void*, llvm::raw_ostream &);
557  static StringRef input(StringRef, void*, uint32_t &);
558};
559
560template<>
561struct ScalarTraits<uint64_t> {
562  static void output(const uint64_t &, void*, llvm::raw_ostream &);
563  static StringRef input(StringRef, void*, uint64_t &);
564};
565
566template<>
567struct ScalarTraits<int8_t> {
568  static void output(const int8_t &, void*, llvm::raw_ostream &);
569  static StringRef input(StringRef, void*, int8_t &);
570};
571
572template<>
573struct ScalarTraits<int16_t> {
574  static void output(const int16_t &, void*, llvm::raw_ostream &);
575  static StringRef input(StringRef, void*, int16_t &);
576};
577
578template<>
579struct ScalarTraits<int32_t> {
580  static void output(const int32_t &, void*, llvm::raw_ostream &);
581  static StringRef input(StringRef, void*, int32_t &);
582};
583
584template<>
585struct ScalarTraits<int64_t> {
586  static void output(const int64_t &, void*, llvm::raw_ostream &);
587  static StringRef input(StringRef, void*, int64_t &);
588};
589
590template<>
591struct ScalarTraits<float> {
592  static void output(const float &, void*, llvm::raw_ostream &);
593  static StringRef input(StringRef, void*, float &);
594};
595
596template<>
597struct ScalarTraits<double> {
598  static void output(const double &, void*, llvm::raw_ostream &);
599  static StringRef input(StringRef, void*, double &);
600};
601
602
603
604// Utility for use within MappingTraits<>::mapping() method
605// to [de]normalize an object for use with YAML conversion.
606template <typename TNorm, typename TFinal>
607struct MappingNormalization {
608  MappingNormalization(IO &i_o, TFinal &Obj)
609      : io(i_o), BufPtr(NULL), Result(Obj) {
610    if ( io.outputting() ) {
611      BufPtr = new (&Buffer) TNorm(io, Obj);
612    }
613    else {
614      BufPtr = new (&Buffer) TNorm(io);
615    }
616  }
617
618  ~MappingNormalization() {
619    if ( ! io.outputting() ) {
620      Result = BufPtr->denormalize(io);
621    }
622    BufPtr->~TNorm();
623  }
624
625  TNorm* operator->() { return BufPtr; }
626
627private:
628  typedef llvm::AlignedCharArrayUnion<TNorm> Storage;
629
630  Storage       Buffer;
631  IO           &io;
632  TNorm        *BufPtr;
633  TFinal       &Result;
634};
635
636
637
638// Utility for use within MappingTraits<>::mapping() method
639// to [de]normalize an object for use with YAML conversion.
640template <typename TNorm, typename TFinal>
641struct MappingNormalizationHeap {
642  MappingNormalizationHeap(IO &i_o, TFinal &Obj)
643    : io(i_o), BufPtr(NULL), Result(Obj) {
644    if ( io.outputting() ) {
645      BufPtr = new (&Buffer) TNorm(io, Obj);
646    }
647    else {
648      BufPtr = new TNorm(io);
649    }
650  }
651
652  ~MappingNormalizationHeap() {
653    if ( io.outputting() ) {
654      BufPtr->~TNorm();
655    }
656    else {
657      Result = BufPtr->denormalize(io);
658    }
659  }
660
661  TNorm* operator->() { return BufPtr; }
662
663private:
664  typedef llvm::AlignedCharArrayUnion<TNorm> Storage;
665
666  Storage       Buffer;
667  IO           &io;
668  TNorm        *BufPtr;
669  TFinal       &Result;
670};
671
672
673
674///
675/// The Input class is used to parse a yaml document into in-memory structs
676/// and vectors.
677///
678/// It works by using YAMLParser to do a syntax parse of the entire yaml
679/// document, then the Input class builds a graph of HNodes which wraps
680/// each yaml Node.  The extra layer is buffering.  The low level yaml
681/// parser only lets you look at each node once.  The buffering layer lets
682/// you search and interate multiple times.  This is necessary because
683/// the mapRequired() method calls may not be in the same order
684/// as the keys in the document.
685///
686class Input : public IO {
687public:
688  // Construct a yaml Input object from a StringRef and optional
689  // user-data. The DiagHandler can be specified to provide
690  // alternative error reporting.
691  Input(StringRef InputContent,
692        void *Ctxt = NULL,
693        SourceMgr::DiagHandlerTy DiagHandler = NULL,
694        void *DiagHandlerCtxt = NULL);
695  ~Input();
696
697  // Check if there was an syntax or semantic error during parsing.
698  llvm::error_code error();
699
700  static bool classof(const IO *io) { return !io->outputting(); }
701
702private:
703  virtual bool outputting() const;
704  virtual bool mapTag(StringRef, bool);
705  virtual void beginMapping();
706  virtual void endMapping();
707  virtual bool preflightKey(const char *, bool, bool, bool &, void *&);
708  virtual void postflightKey(void *);
709  virtual unsigned beginSequence();
710  virtual void endSequence();
711  virtual bool preflightElement(unsigned index, void *&);
712  virtual void postflightElement(void *);
713  virtual unsigned beginFlowSequence();
714  virtual bool preflightFlowElement(unsigned , void *&);
715  virtual void postflightFlowElement(void *);
716  virtual void endFlowSequence();
717  virtual void beginEnumScalar();
718  virtual bool matchEnumScalar(const char*, bool);
719  virtual void endEnumScalar();
720  virtual bool beginBitSetScalar(bool &);
721  virtual bool bitSetMatch(const char *, bool );
722  virtual void endBitSetScalar();
723  virtual void scalarString(StringRef &);
724  virtual void setError(const Twine &message);
725  virtual bool canElideEmptySequence();
726
727  class HNode {
728    virtual void anchor();
729  public:
730    HNode(Node *n) : _node(n) { }
731    virtual ~HNode() { }
732    static inline bool classof(const HNode *) { return true; }
733
734    Node *_node;
735  };
736
737  class EmptyHNode : public HNode {
738    virtual void anchor();
739  public:
740    EmptyHNode(Node *n) : HNode(n) { }
741    static inline bool classof(const HNode *n) {
742      return NullNode::classof(n->_node);
743    }
744    static inline bool classof(const EmptyHNode *) { return true; }
745  };
746
747  class ScalarHNode : public HNode {
748    virtual void anchor();
749  public:
750    ScalarHNode(Node *n, StringRef s) : HNode(n), _value(s) { }
751
752    StringRef value() const { return _value; }
753
754    static inline bool classof(const HNode *n) {
755      return ScalarNode::classof(n->_node);
756    }
757    static inline bool classof(const ScalarHNode *) { return true; }
758  protected:
759    StringRef _value;
760  };
761
762  class MapHNode : public HNode {
763  public:
764    MapHNode(Node *n) : HNode(n) { }
765    virtual ~MapHNode();
766
767    static inline bool classof(const HNode *n) {
768      return MappingNode::classof(n->_node);
769    }
770    static inline bool classof(const MapHNode *) { return true; }
771
772    typedef llvm::StringMap<HNode*> NameToNode;
773
774    bool isValidKey(StringRef key);
775
776    NameToNode                        Mapping;
777    llvm::SmallVector<const char*, 6> ValidKeys;
778  };
779
780  class SequenceHNode : public HNode {
781  public:
782    SequenceHNode(Node *n) : HNode(n) { }
783    virtual ~SequenceHNode();
784
785    static inline bool classof(const HNode *n) {
786      return SequenceNode::classof(n->_node);
787    }
788    static inline bool classof(const SequenceHNode *) { return true; }
789
790    std::vector<HNode*> Entries;
791  };
792
793  Input::HNode *createHNodes(Node *node);
794  void setError(HNode *hnode, const Twine &message);
795  void setError(Node *node, const Twine &message);
796
797
798public:
799  // These are only used by operator>>. They could be private
800  // if those templated things could be made friends.
801  bool setCurrentDocument();
802  void nextDocument();
803
804private:
805  llvm::SourceMgr                  SrcMgr; // must be before Strm
806  OwningPtr<llvm::yaml::Stream>    Strm;
807  OwningPtr<HNode>                 TopNode;
808  llvm::error_code                 EC;
809  llvm::BumpPtrAllocator           StringAllocator;
810  llvm::yaml::document_iterator    DocIterator;
811  std::vector<bool>                BitValuesUsed;
812  HNode                           *CurrentNode;
813  bool                             ScalarMatchFound;
814};
815
816
817
818
819///
820/// The Output class is used to generate a yaml document from in-memory structs
821/// and vectors.
822///
823class Output : public IO {
824public:
825  Output(llvm::raw_ostream &, void *Ctxt=NULL);
826  virtual ~Output();
827
828  static bool classof(const IO *io) { return io->outputting(); }
829
830  virtual bool outputting() const;
831  virtual bool mapTag(StringRef, bool);
832  virtual void beginMapping();
833  virtual void endMapping();
834  virtual bool preflightKey(const char *key, bool, bool, bool &, void *&);
835  virtual void postflightKey(void *);
836  virtual unsigned beginSequence();
837  virtual void endSequence();
838  virtual bool preflightElement(unsigned, void *&);
839  virtual void postflightElement(void *);
840  virtual unsigned beginFlowSequence();
841  virtual bool preflightFlowElement(unsigned, void *&);
842  virtual void postflightFlowElement(void *);
843  virtual void endFlowSequence();
844  virtual void beginEnumScalar();
845  virtual bool matchEnumScalar(const char*, bool);
846  virtual void endEnumScalar();
847  virtual bool beginBitSetScalar(bool &);
848  virtual bool bitSetMatch(const char *, bool );
849  virtual void endBitSetScalar();
850  virtual void scalarString(StringRef &);
851  virtual void setError(const Twine &message);
852  virtual bool canElideEmptySequence();
853public:
854  // These are only used by operator<<. They could be private
855  // if that templated operator could be made a friend.
856  void beginDocuments();
857  bool preflightDocument(unsigned);
858  void postflightDocument();
859  void endDocuments();
860
861private:
862  void output(StringRef s);
863  void outputUpToEndOfLine(StringRef s);
864  void newLineCheck();
865  void outputNewLine();
866  void paddedKey(StringRef key);
867
868  enum InState { inSeq, inFlowSeq, inMapFirstKey, inMapOtherKey };
869
870  llvm::raw_ostream       &Out;
871  SmallVector<InState, 8>  StateStack;
872  int                      Column;
873  int                      ColumnAtFlowStart;
874  bool                     NeedBitValueComma;
875  bool                     NeedFlowSequenceComma;
876  bool                     EnumerationMatchFound;
877  bool                     NeedsNewLine;
878};
879
880
881
882
883/// YAML I/O does conversion based on types. But often native data types
884/// are just a typedef of built in intergral types (e.g. int).  But the C++
885/// type matching system sees through the typedef and all the typedefed types
886/// look like a built in type. This will cause the generic YAML I/O conversion
887/// to be used. To provide better control over the YAML conversion, you can
888/// use this macro instead of typedef.  It will create a class with one field
889/// and automatic conversion operators to and from the base type.
890/// Based on BOOST_STRONG_TYPEDEF
891#define LLVM_YAML_STRONG_TYPEDEF(_base, _type)                                 \
892    struct _type {                                                             \
893        _type() { }                                                            \
894        _type(const _base v) : value(v) { }                                    \
895        _type(const _type &v) : value(v.value) {}                              \
896        _type &operator=(const _type &rhs) { value = rhs.value; return *this; }\
897        _type &operator=(const _base &rhs) { value = rhs; return *this; }      \
898        operator const _base & () const { return value; }                      \
899        bool operator==(const _type &rhs) const { return value == rhs.value; } \
900        bool operator==(const _base &rhs) const { return value == rhs; }       \
901        bool operator<(const _type &rhs) const { return value < rhs.value; }   \
902        _base value;                                                           \
903    };
904
905
906
907///
908/// Use these types instead of uintXX_t in any mapping to have
909/// its yaml output formatted as hexadecimal.
910///
911LLVM_YAML_STRONG_TYPEDEF(uint8_t, Hex8)
912LLVM_YAML_STRONG_TYPEDEF(uint16_t, Hex16)
913LLVM_YAML_STRONG_TYPEDEF(uint32_t, Hex32)
914LLVM_YAML_STRONG_TYPEDEF(uint64_t, Hex64)
915
916
917template<>
918struct ScalarTraits<Hex8> {
919  static void output(const Hex8 &, void*, llvm::raw_ostream &);
920  static StringRef input(StringRef, void*, Hex8 &);
921};
922
923template<>
924struct ScalarTraits<Hex16> {
925  static void output(const Hex16 &, void*, llvm::raw_ostream &);
926  static StringRef input(StringRef, void*, Hex16 &);
927};
928
929template<>
930struct ScalarTraits<Hex32> {
931  static void output(const Hex32 &, void*, llvm::raw_ostream &);
932  static StringRef input(StringRef, void*, Hex32 &);
933};
934
935template<>
936struct ScalarTraits<Hex64> {
937  static void output(const Hex64 &, void*, llvm::raw_ostream &);
938  static StringRef input(StringRef, void*, Hex64 &);
939};
940
941
942// Define non-member operator>> so that Input can stream in a document list.
943template <typename T>
944inline
945typename llvm::enable_if_c<has_DocumentListTraits<T>::value,Input &>::type
946operator>>(Input &yin, T &docList) {
947  int i = 0;
948  while ( yin.setCurrentDocument() ) {
949    yamlize(yin, DocumentListTraits<T>::element(yin, docList, i), true);
950    if ( yin.error() )
951      return yin;
952    yin.nextDocument();
953    ++i;
954  }
955  return yin;
956}
957
958// Define non-member operator>> so that Input can stream in a map as a document.
959template <typename T>
960inline
961typename llvm::enable_if_c<has_MappingTraits<T>::value,Input &>::type
962operator>>(Input &yin, T &docMap) {
963  yin.setCurrentDocument();
964  yamlize(yin, docMap, true);
965  return yin;
966}
967
968// Define non-member operator>> so that Input can stream in a sequence as
969// a document.
970template <typename T>
971inline
972typename llvm::enable_if_c<has_SequenceTraits<T>::value,Input &>::type
973operator>>(Input &yin, T &docSeq) {
974  if (yin.setCurrentDocument())
975    yamlize(yin, docSeq, true);
976  return yin;
977}
978
979// Provide better error message about types missing a trait specialization
980template <typename T>
981inline
982typename llvm::enable_if_c<missingTraits<T>::value,Input &>::type
983operator>>(Input &yin, T &docSeq) {
984  char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
985  return yin;
986}
987
988
989// Define non-member operator<< so that Output can stream out document list.
990template <typename T>
991inline
992typename llvm::enable_if_c<has_DocumentListTraits<T>::value,Output &>::type
993operator<<(Output &yout, T &docList) {
994  yout.beginDocuments();
995  const size_t count = DocumentListTraits<T>::size(yout, docList);
996  for(size_t i=0; i < count; ++i) {
997    if ( yout.preflightDocument(i) ) {
998      yamlize(yout, DocumentListTraits<T>::element(yout, docList, i), true);
999      yout.postflightDocument();
1000    }
1001  }
1002  yout.endDocuments();
1003  return yout;
1004}
1005
1006// Define non-member operator<< so that Output can stream out a map.
1007template <typename T>
1008inline
1009typename llvm::enable_if_c<has_MappingTraits<T>::value,Output &>::type
1010operator<<(Output &yout, T &map) {
1011  yout.beginDocuments();
1012  if ( yout.preflightDocument(0) ) {
1013    yamlize(yout, map, true);
1014    yout.postflightDocument();
1015  }
1016  yout.endDocuments();
1017  return yout;
1018}
1019
1020// Define non-member operator<< so that Output can stream out a sequence.
1021template <typename T>
1022inline
1023typename llvm::enable_if_c<has_SequenceTraits<T>::value,Output &>::type
1024operator<<(Output &yout, T &seq) {
1025  yout.beginDocuments();
1026  if ( yout.preflightDocument(0) ) {
1027    yamlize(yout, seq, true);
1028    yout.postflightDocument();
1029  }
1030  yout.endDocuments();
1031  return yout;
1032}
1033
1034// Provide better error message about types missing a trait specialization
1035template <typename T>
1036inline
1037typename llvm::enable_if_c<missingTraits<T>::value,Output &>::type
1038operator<<(Output &yout, T &seq) {
1039  char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
1040  return yout;
1041}
1042
1043
1044} // namespace yaml
1045} // namespace llvm
1046
1047
1048/// Utility for declaring that a std::vector of a particular type
1049/// should be considered a YAML sequence.
1050#define LLVM_YAML_IS_SEQUENCE_VECTOR(_type)                                 \
1051  namespace llvm {                                                          \
1052  namespace yaml {                                                          \
1053    template<>                                                              \
1054    struct SequenceTraits< std::vector<_type> > {                           \
1055      static size_t size(IO &io, std::vector<_type> &seq) {                 \
1056        return seq.size();                                                  \
1057      }                                                                     \
1058      static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\
1059        if ( index >= seq.size() )                                          \
1060          seq.resize(index+1);                                              \
1061        return seq[index];                                                  \
1062      }                                                                     \
1063    };                                                                      \
1064  }                                                                         \
1065  }
1066
1067/// Utility for declaring that a std::vector of a particular type
1068/// should be considered a YAML flow sequence.
1069#define LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(_type)                            \
1070  namespace llvm {                                                          \
1071  namespace yaml {                                                          \
1072    template<>                                                              \
1073    struct SequenceTraits< std::vector<_type> > {                           \
1074      static size_t size(IO &io, std::vector<_type> &seq) {                 \
1075        return seq.size();                                                  \
1076      }                                                                     \
1077      static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\
1078        if ( index >= seq.size() )                                          \
1079          seq.resize(index+1);                                              \
1080        return seq[index];                                                  \
1081      }                                                                     \
1082      static const bool flow = true;                                        \
1083    };                                                                      \
1084  }                                                                         \
1085  }
1086
1087/// Utility for declaring that a std::vector of a particular type
1088/// should be considered a YAML document list.
1089#define LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(_type)                            \
1090  namespace llvm {                                                          \
1091  namespace yaml {                                                          \
1092    template<>                                                              \
1093    struct DocumentListTraits< std::vector<_type> > {                       \
1094      static size_t size(IO &io, std::vector<_type> &seq) {                 \
1095        return seq.size();                                                  \
1096      }                                                                     \
1097      static _type& element(IO &io, std::vector<_type> &seq, size_t index) {\
1098        if ( index >= seq.size() )                                          \
1099          seq.resize(index+1);                                              \
1100        return seq[index];                                                  \
1101      }                                                                     \
1102    };                                                                      \
1103  }                                                                         \
1104  }
1105
1106
1107
1108#endif // LLVM_SUPPORT_YAMLTRAITS_H
1109