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