blob: 6836aa2aa067b158125834eb5728fb5b80331304 [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===- 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#include "llvm/ADT/Optional.h"
14#include "llvm/ADT/SmallVector.h"
15#include "llvm/ADT/StringExtras.h"
16#include "llvm/ADT/StringMap.h"
17#include "llvm/ADT/StringRef.h"
18#include "llvm/ADT/Twine.h"
19#include "llvm/Support/AlignOf.h"
20#include "llvm/Support/Allocator.h"
21#include "llvm/Support/Endian.h"
22#include "llvm/Support/Regex.h"
23#include "llvm/Support/SourceMgr.h"
24#include "llvm/Support/YAMLParser.h"
25#include "llvm/Support/raw_ostream.h"
26#include <cassert>
27#include <cctype>
28#include <cstddef>
29#include <cstdint>
Andrew Scull0372a572018-11-16 15:47:06 +000030#include <iterator>
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010031#include <map>
32#include <memory>
33#include <new>
34#include <string>
35#include <system_error>
36#include <type_traits>
37#include <vector>
38
39namespace llvm {
40namespace yaml {
41
42struct EmptyContext {};
43
44/// This class should be specialized by any type that needs to be converted
45/// to/from a YAML mapping. For example:
46///
47/// struct MappingTraits<MyStruct> {
48/// static void mapping(IO &io, MyStruct &s) {
49/// io.mapRequired("name", s.name);
50/// io.mapRequired("size", s.size);
51/// io.mapOptional("age", s.age);
52/// }
53/// };
54template<class T>
55struct MappingTraits {
56 // Must provide:
57 // static void mapping(IO &io, T &fields);
58 // Optionally may provide:
59 // static StringRef validate(IO &io, T &fields);
60 //
61 // The optional flow flag will cause generated YAML to use a flow mapping
62 // (e.g. { a: 0, b: 1 }):
63 // static const bool flow = true;
64};
65
66/// This class is similar to MappingTraits<T> but allows you to pass in
67/// additional context for each map operation. For example:
68///
69/// struct MappingContextTraits<MyStruct, MyContext> {
70/// static void mapping(IO &io, MyStruct &s, MyContext &c) {
71/// io.mapRequired("name", s.name);
72/// io.mapRequired("size", s.size);
73/// io.mapOptional("age", s.age);
74/// ++c.TimesMapped;
75/// }
76/// };
77template <class T, class Context> struct MappingContextTraits {
78 // Must provide:
79 // static void mapping(IO &io, T &fields, Context &Ctx);
80 // Optionally may provide:
81 // static StringRef validate(IO &io, T &fields, Context &Ctx);
82 //
83 // The optional flow flag will cause generated YAML to use a flow mapping
84 // (e.g. { a: 0, b: 1 }):
85 // static const bool flow = true;
86};
87
88/// This class should be specialized by any integral type that converts
89/// to/from a YAML scalar where there is a one-to-one mapping between
90/// in-memory values and a string in YAML. For example:
91///
92/// struct ScalarEnumerationTraits<Colors> {
93/// static void enumeration(IO &io, Colors &value) {
94/// io.enumCase(value, "red", cRed);
95/// io.enumCase(value, "blue", cBlue);
96/// io.enumCase(value, "green", cGreen);
97/// }
98/// };
99template<typename T>
100struct ScalarEnumerationTraits {
101 // Must provide:
102 // static void enumeration(IO &io, T &value);
103};
104
105/// This class should be specialized by any integer type that is a union
106/// of bit values and the YAML representation is a flow sequence of
107/// strings. For example:
108///
109/// struct ScalarBitSetTraits<MyFlags> {
110/// static void bitset(IO &io, MyFlags &value) {
111/// io.bitSetCase(value, "big", flagBig);
112/// io.bitSetCase(value, "flat", flagFlat);
113/// io.bitSetCase(value, "round", flagRound);
114/// }
115/// };
116template<typename T>
117struct ScalarBitSetTraits {
118 // Must provide:
119 // static void bitset(IO &io, T &value);
120};
121
122/// Describe which type of quotes should be used when quoting is necessary.
123/// Some non-printable characters need to be double-quoted, while some others
124/// are fine with simple-quoting, and some don't need any quoting.
125enum class QuotingType { None, Single, Double };
126
127/// This class should be specialized by type that requires custom conversion
128/// to/from a yaml scalar. For example:
129///
130/// template<>
131/// struct ScalarTraits<MyType> {
132/// static void output(const MyType &val, void*, llvm::raw_ostream &out) {
133/// // stream out custom formatting
134/// out << llvm::format("%x", val);
135/// }
136/// static StringRef input(StringRef scalar, void*, MyType &value) {
137/// // parse scalar and set `value`
138/// // return empty string on success, or error string
139/// return StringRef();
140/// }
141/// static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
142/// };
143template<typename T>
144struct ScalarTraits {
145 // Must provide:
146 //
147 // Function to write the value as a string:
148 //static void output(const T &value, void *ctxt, llvm::raw_ostream &out);
149 //
150 // Function to convert a string to a value. Returns the empty
151 // StringRef on success or an error string if string is malformed:
152 //static StringRef input(StringRef scalar, void *ctxt, T &value);
153 //
154 // Function to determine if the value should be quoted.
155 //static QuotingType mustQuote(StringRef);
156};
157
158/// This class should be specialized by type that requires custom conversion
159/// to/from a YAML literal block scalar. For example:
160///
161/// template <>
162/// struct BlockScalarTraits<MyType> {
163/// static void output(const MyType &Value, void*, llvm::raw_ostream &Out)
164/// {
165/// // stream out custom formatting
166/// Out << Val;
167/// }
168/// static StringRef input(StringRef Scalar, void*, MyType &Value) {
169/// // parse scalar and set `value`
170/// // return empty string on success, or error string
171/// return StringRef();
172/// }
173/// };
174template <typename T>
175struct BlockScalarTraits {
176 // Must provide:
177 //
178 // Function to write the value as a string:
179 // static void output(const T &Value, void *ctx, llvm::raw_ostream &Out);
180 //
181 // Function to convert a string to a value. Returns the empty
182 // StringRef on success or an error string if string is malformed:
183 // static StringRef input(StringRef Scalar, void *ctxt, T &Value);
184};
185
186/// This class should be specialized by any type that needs to be converted
187/// to/from a YAML sequence. For example:
188///
189/// template<>
190/// struct SequenceTraits<MyContainer> {
191/// static size_t size(IO &io, MyContainer &seq) {
192/// return seq.size();
193/// }
194/// static MyType& element(IO &, MyContainer &seq, size_t index) {
195/// if ( index >= seq.size() )
196/// seq.resize(index+1);
197/// return seq[index];
198/// }
199/// };
200template<typename T, typename EnableIf = void>
201struct SequenceTraits {
202 // Must provide:
203 // static size_t size(IO &io, T &seq);
204 // static T::value_type& element(IO &io, T &seq, size_t index);
205 //
206 // The following is option and will cause generated YAML to use
207 // a flow sequence (e.g. [a,b,c]).
208 // static const bool flow = true;
209};
210
211/// This class should be specialized by any type for which vectors of that
212/// type need to be converted to/from a YAML sequence.
213template<typename T, typename EnableIf = void>
214struct SequenceElementTraits {
215 // Must provide:
216 // static const bool flow;
217};
218
219/// This class should be specialized by any type that needs to be converted
220/// to/from a list of YAML documents.
221template<typename T>
222struct DocumentListTraits {
223 // Must provide:
224 // static size_t size(IO &io, T &seq);
225 // static T::value_type& element(IO &io, T &seq, size_t index);
226};
227
228/// This class should be specialized by any type that needs to be converted
229/// to/from a YAML mapping in the case where the names of the keys are not known
230/// in advance, e.g. a string map.
231template <typename T>
232struct CustomMappingTraits {
233 // static void inputOne(IO &io, StringRef key, T &elem);
234 // static void output(IO &io, T &elem);
235};
236
237// Only used for better diagnostics of missing traits
238template <typename T>
239struct MissingTrait;
240
241// Test if ScalarEnumerationTraits<T> is defined on type T.
242template <class T>
243struct has_ScalarEnumerationTraits
244{
245 using Signature_enumeration = void (*)(class IO&, T&);
246
247 template <typename U>
248 static char test(SameType<Signature_enumeration, &U::enumeration>*);
249
250 template <typename U>
251 static double test(...);
252
253public:
254 static bool const value =
255 (sizeof(test<ScalarEnumerationTraits<T>>(nullptr)) == 1);
256};
257
258// Test if ScalarBitSetTraits<T> is defined on type T.
259template <class T>
260struct has_ScalarBitSetTraits
261{
262 using Signature_bitset = void (*)(class IO&, T&);
263
264 template <typename U>
265 static char test(SameType<Signature_bitset, &U::bitset>*);
266
267 template <typename U>
268 static double test(...);
269
270public:
271 static bool const value = (sizeof(test<ScalarBitSetTraits<T>>(nullptr)) == 1);
272};
273
274// Test if ScalarTraits<T> is defined on type T.
275template <class T>
276struct has_ScalarTraits
277{
278 using Signature_input = StringRef (*)(StringRef, void*, T&);
279 using Signature_output = void (*)(const T&, void*, raw_ostream&);
280 using Signature_mustQuote = QuotingType (*)(StringRef);
281
282 template <typename U>
283 static char test(SameType<Signature_input, &U::input> *,
284 SameType<Signature_output, &U::output> *,
285 SameType<Signature_mustQuote, &U::mustQuote> *);
286
287 template <typename U>
288 static double test(...);
289
290public:
291 static bool const value =
292 (sizeof(test<ScalarTraits<T>>(nullptr, nullptr, nullptr)) == 1);
293};
294
295// Test if BlockScalarTraits<T> is defined on type T.
296template <class T>
297struct has_BlockScalarTraits
298{
299 using Signature_input = StringRef (*)(StringRef, void *, T &);
300 using Signature_output = void (*)(const T &, void *, raw_ostream &);
301
302 template <typename U>
303 static char test(SameType<Signature_input, &U::input> *,
304 SameType<Signature_output, &U::output> *);
305
306 template <typename U>
307 static double test(...);
308
309public:
310 static bool const value =
311 (sizeof(test<BlockScalarTraits<T>>(nullptr, nullptr)) == 1);
312};
313
314// Test if MappingContextTraits<T> is defined on type T.
315template <class T, class Context> struct has_MappingTraits {
316 using Signature_mapping = void (*)(class IO &, T &, Context &);
317
318 template <typename U>
319 static char test(SameType<Signature_mapping, &U::mapping>*);
320
321 template <typename U>
322 static double test(...);
323
324public:
325 static bool const value =
326 (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1);
327};
328
329// Test if MappingTraits<T> is defined on type T.
330template <class T> struct has_MappingTraits<T, EmptyContext> {
331 using Signature_mapping = void (*)(class IO &, T &);
332
333 template <typename U>
334 static char test(SameType<Signature_mapping, &U::mapping> *);
335
336 template <typename U> static double test(...);
337
338public:
339 static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1);
340};
341
342// Test if MappingContextTraits<T>::validate() is defined on type T.
343template <class T, class Context> struct has_MappingValidateTraits {
344 using Signature_validate = StringRef (*)(class IO &, T &, Context &);
345
346 template <typename U>
347 static char test(SameType<Signature_validate, &U::validate>*);
348
349 template <typename U>
350 static double test(...);
351
352public:
353 static bool const value =
354 (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1);
355};
356
357// Test if MappingTraits<T>::validate() is defined on type T.
358template <class T> struct has_MappingValidateTraits<T, EmptyContext> {
359 using Signature_validate = StringRef (*)(class IO &, T &);
360
361 template <typename U>
362 static char test(SameType<Signature_validate, &U::validate> *);
363
364 template <typename U> static double test(...);
365
366public:
367 static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1);
368};
369
370// Test if SequenceTraits<T> is defined on type T.
371template <class T>
372struct has_SequenceMethodTraits
373{
374 using Signature_size = size_t (*)(class IO&, T&);
375
376 template <typename U>
377 static char test(SameType<Signature_size, &U::size>*);
378
379 template <typename U>
380 static double test(...);
381
382public:
383 static bool const value = (sizeof(test<SequenceTraits<T>>(nullptr)) == 1);
384};
385
386// Test if CustomMappingTraits<T> is defined on type T.
387template <class T>
388struct has_CustomMappingTraits
389{
390 using Signature_input = void (*)(IO &io, StringRef key, T &v);
391
392 template <typename U>
393 static char test(SameType<Signature_input, &U::inputOne>*);
394
395 template <typename U>
396 static double test(...);
397
398public:
399 static bool const value =
400 (sizeof(test<CustomMappingTraits<T>>(nullptr)) == 1);
401};
402
403// has_FlowTraits<int> will cause an error with some compilers because
404// it subclasses int. Using this wrapper only instantiates the
405// real has_FlowTraits only if the template type is a class.
406template <typename T, bool Enabled = std::is_class<T>::value>
407class has_FlowTraits
408{
409public:
410 static const bool value = false;
411};
412
413// Some older gcc compilers don't support straight forward tests
414// for members, so test for ambiguity cause by the base and derived
415// classes both defining the member.
416template <class T>
417struct has_FlowTraits<T, true>
418{
419 struct Fallback { bool flow; };
420 struct Derived : T, Fallback { };
421
422 template<typename C>
423 static char (&f(SameType<bool Fallback::*, &C::flow>*))[1];
424
425 template<typename C>
426 static char (&f(...))[2];
427
428public:
429 static bool const value = sizeof(f<Derived>(nullptr)) == 2;
430};
431
432// Test if SequenceTraits<T> is defined on type T
433template<typename T>
434struct has_SequenceTraits : public std::integral_constant<bool,
435 has_SequenceMethodTraits<T>::value > { };
436
437// Test if DocumentListTraits<T> is defined on type T
438template <class T>
439struct has_DocumentListTraits
440{
441 using Signature_size = size_t (*)(class IO &, T &);
442
443 template <typename U>
444 static char test(SameType<Signature_size, &U::size>*);
445
446 template <typename U>
447 static double test(...);
448
449public:
450 static bool const value = (sizeof(test<DocumentListTraits<T>>(nullptr))==1);
451};
452
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100453inline bool isNumeric(StringRef S) {
Andrew Scull0372a572018-11-16 15:47:06 +0000454 const static auto skipDigits = [](StringRef Input) {
455 return Input.drop_front(
456 std::min(Input.find_first_not_of("0123456789"), Input.size()));
457 };
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100458
Andrew Scull0372a572018-11-16 15:47:06 +0000459 // Make S.front() and S.drop_front().front() (if S.front() is [+-]) calls
460 // safe.
461 if (S.empty() || S.equals("+") || S.equals("-"))
462 return false;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100463
464 if (S.equals(".nan") || S.equals(".NaN") || S.equals(".NAN"))
465 return true;
466
Andrew Scull0372a572018-11-16 15:47:06 +0000467 // Infinity and decimal numbers can be prefixed with sign.
468 StringRef Tail = (S.front() == '-' || S.front() == '+') ? S.drop_front() : S;
469
470 // Check for infinity first, because checking for hex and oct numbers is more
471 // expensive.
472 if (Tail.equals(".inf") || Tail.equals(".Inf") || Tail.equals(".INF"))
473 return true;
474
475 // Section 10.3.2 Tag Resolution
476 // YAML 1.2 Specification prohibits Base 8 and Base 16 numbers prefixed with
477 // [-+], so S should be used instead of Tail.
478 if (S.startswith("0o"))
479 return S.size() > 2 &&
480 S.drop_front(2).find_first_not_of("01234567") == StringRef::npos;
481
482 if (S.startswith("0x"))
483 return S.size() > 2 && S.drop_front(2).find_first_not_of(
484 "0123456789abcdefABCDEF") == StringRef::npos;
485
486 // Parse float: [-+]? (\. [0-9]+ | [0-9]+ (\. [0-9]* )?) ([eE] [-+]? [0-9]+)?
487 S = Tail;
488
489 // Handle cases when the number starts with '.' and hence needs at least one
490 // digit after dot (as opposed by number which has digits before the dot), but
491 // doesn't have one.
492 if (S.startswith(".") &&
493 (S.equals(".") ||
494 (S.size() > 1 && std::strchr("0123456789", S[1]) == nullptr)))
495 return false;
496
497 if (S.startswith("E") || S.startswith("e"))
498 return false;
499
500 enum ParseState {
501 Default,
502 FoundDot,
503 FoundExponent,
504 };
505 ParseState State = Default;
506
507 S = skipDigits(S);
508
509 // Accept decimal integer.
510 if (S.empty())
511 return true;
512
513 if (S.front() == '.') {
514 State = FoundDot;
515 S = S.drop_front();
516 } else if (S.front() == 'e' || S.front() == 'E') {
517 State = FoundExponent;
518 S = S.drop_front();
519 } else {
520 return false;
521 }
522
523 if (State == FoundDot) {
524 S = skipDigits(S);
525 if (S.empty())
526 return true;
527
528 if (S.front() == 'e' || S.front() == 'E') {
529 State = FoundExponent;
530 S = S.drop_front();
531 } else {
532 return false;
533 }
534 }
535
536 assert(State == FoundExponent && "Should have found exponent at this point.");
537 if (S.empty())
538 return false;
539
540 if (S.front() == '+' || S.front() == '-') {
541 S = S.drop_front();
542 if (S.empty())
543 return false;
544 }
545
546 return skipDigits(S).empty();
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100547}
548
549inline bool isNull(StringRef S) {
550 return S.equals("null") || S.equals("Null") || S.equals("NULL") ||
551 S.equals("~");
552}
553
554inline bool isBool(StringRef S) {
555 return S.equals("true") || S.equals("True") || S.equals("TRUE") ||
556 S.equals("false") || S.equals("False") || S.equals("FALSE");
557}
558
559// 5.1. Character Set
560// The allowed character range explicitly excludes the C0 control block #x0-#x1F
561// (except for TAB #x9, LF #xA, and CR #xD which are allowed), DEL #x7F, the C1
562// control block #x80-#x9F (except for NEL #x85 which is allowed), the surrogate
563// block #xD800-#xDFFF, #xFFFE, and #xFFFF.
564inline QuotingType needsQuotes(StringRef S) {
565 if (S.empty())
566 return QuotingType::Single;
567 if (isspace(S.front()) || isspace(S.back()))
568 return QuotingType::Single;
569 if (isNull(S))
570 return QuotingType::Single;
571 if (isBool(S))
572 return QuotingType::Single;
573 if (isNumeric(S))
574 return QuotingType::Single;
575
576 // 7.3.3 Plain Style
577 // Plain scalars must not begin with most indicators, as this would cause
578 // ambiguity with other YAML constructs.
579 static constexpr char Indicators[] = R"(-?:\,[]{}#&*!|>'"%@`)";
580 if (S.find_first_of(Indicators) == 0)
581 return QuotingType::Single;
582
583 QuotingType MaxQuotingNeeded = QuotingType::None;
584 for (unsigned char C : S) {
585 // Alphanum is safe.
586 if (isAlnum(C))
587 continue;
588
589 switch (C) {
590 // Safe scalar characters.
591 case '_':
592 case '-':
593 case '/':
594 case '^':
595 case '.':
596 case ',':
597 case ' ':
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100598 // TAB (0x9) is allowed in unquoted strings.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100599 case 0x9:
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100600 continue;
601 // LF(0xA) and CR(0xD) may delimit values and so require at least single
602 // quotes.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100603 case 0xA:
604 case 0xD:
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100605 MaxQuotingNeeded = QuotingType::Single;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100606 continue;
607 // DEL (0x7F) are excluded from the allowed character range.
608 case 0x7F:
609 return QuotingType::Double;
610 default: {
611 // C0 control block (0x0 - 0x1F) is excluded from the allowed character
612 // range.
613 if (C <= 0x1F)
614 return QuotingType::Double;
615
616 // Always double quote UTF-8.
617 if ((C & 0x80) != 0)
618 return QuotingType::Double;
619
620 // The character is not safe, at least simple quoting needed.
621 MaxQuotingNeeded = QuotingType::Single;
622 }
623 }
624 }
625
626 return MaxQuotingNeeded;
627}
628
629template <typename T, typename Context>
630struct missingTraits
631 : public std::integral_constant<bool,
632 !has_ScalarEnumerationTraits<T>::value &&
633 !has_ScalarBitSetTraits<T>::value &&
634 !has_ScalarTraits<T>::value &&
635 !has_BlockScalarTraits<T>::value &&
636 !has_MappingTraits<T, Context>::value &&
637 !has_SequenceTraits<T>::value &&
638 !has_CustomMappingTraits<T>::value &&
639 !has_DocumentListTraits<T>::value> {};
640
641template <typename T, typename Context>
642struct validatedMappingTraits
643 : public std::integral_constant<
644 bool, has_MappingTraits<T, Context>::value &&
645 has_MappingValidateTraits<T, Context>::value> {};
646
647template <typename T, typename Context>
648struct unvalidatedMappingTraits
649 : public std::integral_constant<
650 bool, has_MappingTraits<T, Context>::value &&
651 !has_MappingValidateTraits<T, Context>::value> {};
652
653// Base class for Input and Output.
654class IO {
655public:
656 IO(void *Ctxt = nullptr);
657 virtual ~IO();
658
659 virtual bool outputting() = 0;
660
661 virtual unsigned beginSequence() = 0;
662 virtual bool preflightElement(unsigned, void *&) = 0;
663 virtual void postflightElement(void*) = 0;
664 virtual void endSequence() = 0;
665 virtual bool canElideEmptySequence() = 0;
666
667 virtual unsigned beginFlowSequence() = 0;
668 virtual bool preflightFlowElement(unsigned, void *&) = 0;
669 virtual void postflightFlowElement(void*) = 0;
670 virtual void endFlowSequence() = 0;
671
672 virtual bool mapTag(StringRef Tag, bool Default=false) = 0;
673 virtual void beginMapping() = 0;
674 virtual void endMapping() = 0;
675 virtual bool preflightKey(const char*, bool, bool, bool &, void *&) = 0;
676 virtual void postflightKey(void*) = 0;
677 virtual std::vector<StringRef> keys() = 0;
678
679 virtual void beginFlowMapping() = 0;
680 virtual void endFlowMapping() = 0;
681
682 virtual void beginEnumScalar() = 0;
683 virtual bool matchEnumScalar(const char*, bool) = 0;
684 virtual bool matchEnumFallback() = 0;
685 virtual void endEnumScalar() = 0;
686
687 virtual bool beginBitSetScalar(bool &) = 0;
688 virtual bool bitSetMatch(const char*, bool) = 0;
689 virtual void endBitSetScalar() = 0;
690
691 virtual void scalarString(StringRef &, QuotingType) = 0;
692 virtual void blockScalarString(StringRef &) = 0;
693
694 virtual void setError(const Twine &) = 0;
695
696 template <typename T>
697 void enumCase(T &Val, const char* Str, const T ConstVal) {
698 if ( matchEnumScalar(Str, outputting() && Val == ConstVal) ) {
699 Val = ConstVal;
700 }
701 }
702
703 // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF
704 template <typename T>
705 void enumCase(T &Val, const char* Str, const uint32_t ConstVal) {
706 if ( matchEnumScalar(Str, outputting() && Val == static_cast<T>(ConstVal)) ) {
707 Val = ConstVal;
708 }
709 }
710
711 template <typename FBT, typename T>
712 void enumFallback(T &Val) {
713 if (matchEnumFallback()) {
714 EmptyContext Context;
715 // FIXME: Force integral conversion to allow strong typedefs to convert.
716 FBT Res = static_cast<typename FBT::BaseType>(Val);
717 yamlize(*this, Res, true, Context);
718 Val = static_cast<T>(static_cast<typename FBT::BaseType>(Res));
719 }
720 }
721
722 template <typename T>
723 void bitSetCase(T &Val, const char* Str, const T ConstVal) {
724 if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) {
725 Val = static_cast<T>(Val | ConstVal);
726 }
727 }
728
729 // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF
730 template <typename T>
731 void bitSetCase(T &Val, const char* Str, const uint32_t ConstVal) {
732 if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) {
733 Val = static_cast<T>(Val | ConstVal);
734 }
735 }
736
737 template <typename T>
738 void maskedBitSetCase(T &Val, const char *Str, T ConstVal, T Mask) {
739 if (bitSetMatch(Str, outputting() && (Val & Mask) == ConstVal))
740 Val = Val | ConstVal;
741 }
742
743 template <typename T>
744 void maskedBitSetCase(T &Val, const char *Str, uint32_t ConstVal,
745 uint32_t Mask) {
746 if (bitSetMatch(Str, outputting() && (Val & Mask) == ConstVal))
747 Val = Val | ConstVal;
748 }
749
750 void *getContext();
751 void setContext(void *);
752
753 template <typename T> void mapRequired(const char *Key, T &Val) {
754 EmptyContext Ctx;
755 this->processKey(Key, Val, true, Ctx);
756 }
757
758 template <typename T, typename Context>
759 void mapRequired(const char *Key, T &Val, Context &Ctx) {
760 this->processKey(Key, Val, true, Ctx);
761 }
762
763 template <typename T> void mapOptional(const char *Key, T &Val) {
764 EmptyContext Ctx;
765 mapOptionalWithContext(Key, Val, Ctx);
766 }
767
768 template <typename T>
769 void mapOptional(const char *Key, T &Val, const T &Default) {
770 EmptyContext Ctx;
771 mapOptionalWithContext(Key, Val, Default, Ctx);
772 }
773
774 template <typename T, typename Context>
775 typename std::enable_if<has_SequenceTraits<T>::value, void>::type
776 mapOptionalWithContext(const char *Key, T &Val, Context &Ctx) {
777 // omit key/value instead of outputting empty sequence
778 if (this->canElideEmptySequence() && !(Val.begin() != Val.end()))
779 return;
780 this->processKey(Key, Val, false, Ctx);
781 }
782
783 template <typename T, typename Context>
784 void mapOptionalWithContext(const char *Key, Optional<T> &Val, Context &Ctx) {
785 this->processKeyWithDefault(Key, Val, Optional<T>(), /*Required=*/false,
786 Ctx);
787 }
788
789 template <typename T, typename Context>
790 typename std::enable_if<!has_SequenceTraits<T>::value, void>::type
791 mapOptionalWithContext(const char *Key, T &Val, Context &Ctx) {
792 this->processKey(Key, Val, false, Ctx);
793 }
794
795 template <typename T, typename Context>
796 void mapOptionalWithContext(const char *Key, T &Val, const T &Default,
797 Context &Ctx) {
798 this->processKeyWithDefault(Key, Val, Default, false, Ctx);
799 }
800
801private:
802 template <typename T, typename Context>
803 void processKeyWithDefault(const char *Key, Optional<T> &Val,
804 const Optional<T> &DefaultValue, bool Required,
805 Context &Ctx) {
806 assert(DefaultValue.hasValue() == false &&
807 "Optional<T> shouldn't have a value!");
808 void *SaveInfo;
809 bool UseDefault = true;
810 const bool sameAsDefault = outputting() && !Val.hasValue();
811 if (!outputting() && !Val.hasValue())
812 Val = T();
813 if (Val.hasValue() &&
814 this->preflightKey(Key, Required, sameAsDefault, UseDefault,
815 SaveInfo)) {
816 yamlize(*this, Val.getValue(), Required, Ctx);
817 this->postflightKey(SaveInfo);
818 } else {
819 if (UseDefault)
820 Val = DefaultValue;
821 }
822 }
823
824 template <typename T, typename Context>
825 void processKeyWithDefault(const char *Key, T &Val, const T &DefaultValue,
826 bool Required, Context &Ctx) {
827 void *SaveInfo;
828 bool UseDefault;
829 const bool sameAsDefault = outputting() && Val == DefaultValue;
830 if ( this->preflightKey(Key, Required, sameAsDefault, UseDefault,
831 SaveInfo) ) {
832 yamlize(*this, Val, Required, Ctx);
833 this->postflightKey(SaveInfo);
834 }
835 else {
836 if ( UseDefault )
837 Val = DefaultValue;
838 }
839 }
840
841 template <typename T, typename Context>
842 void processKey(const char *Key, T &Val, bool Required, Context &Ctx) {
843 void *SaveInfo;
844 bool UseDefault;
845 if ( this->preflightKey(Key, Required, false, UseDefault, SaveInfo) ) {
846 yamlize(*this, Val, Required, Ctx);
847 this->postflightKey(SaveInfo);
848 }
849 }
850
851private:
852 void *Ctxt;
853};
854
855namespace detail {
856
857template <typename T, typename Context>
858void doMapping(IO &io, T &Val, Context &Ctx) {
859 MappingContextTraits<T, Context>::mapping(io, Val, Ctx);
860}
861
862template <typename T> void doMapping(IO &io, T &Val, EmptyContext &Ctx) {
863 MappingTraits<T>::mapping(io, Val);
864}
865
866} // end namespace detail
867
868template <typename T>
869typename std::enable_if<has_ScalarEnumerationTraits<T>::value, void>::type
870yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
871 io.beginEnumScalar();
872 ScalarEnumerationTraits<T>::enumeration(io, Val);
873 io.endEnumScalar();
874}
875
876template <typename T>
877typename std::enable_if<has_ScalarBitSetTraits<T>::value, void>::type
878yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
879 bool DoClear;
880 if ( io.beginBitSetScalar(DoClear) ) {
881 if ( DoClear )
882 Val = static_cast<T>(0);
883 ScalarBitSetTraits<T>::bitset(io, Val);
884 io.endBitSetScalar();
885 }
886}
887
888template <typename T>
889typename std::enable_if<has_ScalarTraits<T>::value, void>::type
890yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
891 if ( io.outputting() ) {
892 std::string Storage;
893 raw_string_ostream Buffer(Storage);
894 ScalarTraits<T>::output(Val, io.getContext(), Buffer);
895 StringRef Str = Buffer.str();
896 io.scalarString(Str, ScalarTraits<T>::mustQuote(Str));
897 }
898 else {
899 StringRef Str;
900 io.scalarString(Str, ScalarTraits<T>::mustQuote(Str));
901 StringRef Result = ScalarTraits<T>::input(Str, io.getContext(), Val);
902 if ( !Result.empty() ) {
903 io.setError(Twine(Result));
904 }
905 }
906}
907
908template <typename T>
909typename std::enable_if<has_BlockScalarTraits<T>::value, void>::type
910yamlize(IO &YamlIO, T &Val, bool, EmptyContext &Ctx) {
911 if (YamlIO.outputting()) {
912 std::string Storage;
913 raw_string_ostream Buffer(Storage);
914 BlockScalarTraits<T>::output(Val, YamlIO.getContext(), Buffer);
915 StringRef Str = Buffer.str();
916 YamlIO.blockScalarString(Str);
917 } else {
918 StringRef Str;
919 YamlIO.blockScalarString(Str);
920 StringRef Result =
921 BlockScalarTraits<T>::input(Str, YamlIO.getContext(), Val);
922 if (!Result.empty())
923 YamlIO.setError(Twine(Result));
924 }
925}
926
927template <typename T, typename Context>
928typename std::enable_if<validatedMappingTraits<T, Context>::value, void>::type
929yamlize(IO &io, T &Val, bool, Context &Ctx) {
930 if (has_FlowTraits<MappingTraits<T>>::value)
931 io.beginFlowMapping();
932 else
933 io.beginMapping();
934 if (io.outputting()) {
935 StringRef Err = MappingTraits<T>::validate(io, Val);
936 if (!Err.empty()) {
937 errs() << Err << "\n";
938 assert(Err.empty() && "invalid struct trying to be written as yaml");
939 }
940 }
941 detail::doMapping(io, Val, Ctx);
942 if (!io.outputting()) {
943 StringRef Err = MappingTraits<T>::validate(io, Val);
944 if (!Err.empty())
945 io.setError(Err);
946 }
947 if (has_FlowTraits<MappingTraits<T>>::value)
948 io.endFlowMapping();
949 else
950 io.endMapping();
951}
952
953template <typename T, typename Context>
954typename std::enable_if<unvalidatedMappingTraits<T, Context>::value, void>::type
955yamlize(IO &io, T &Val, bool, Context &Ctx) {
956 if (has_FlowTraits<MappingTraits<T>>::value) {
957 io.beginFlowMapping();
958 detail::doMapping(io, Val, Ctx);
959 io.endFlowMapping();
960 } else {
961 io.beginMapping();
962 detail::doMapping(io, Val, Ctx);
963 io.endMapping();
964 }
965}
966
967template <typename T>
968typename std::enable_if<has_CustomMappingTraits<T>::value, void>::type
969yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
970 if ( io.outputting() ) {
971 io.beginMapping();
972 CustomMappingTraits<T>::output(io, Val);
973 io.endMapping();
974 } else {
975 io.beginMapping();
976 for (StringRef key : io.keys())
977 CustomMappingTraits<T>::inputOne(io, key, Val);
978 io.endMapping();
979 }
980}
981
982template <typename T>
983typename std::enable_if<missingTraits<T, EmptyContext>::value, void>::type
984yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
985 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
986}
987
988template <typename T, typename Context>
989typename std::enable_if<has_SequenceTraits<T>::value, void>::type
990yamlize(IO &io, T &Seq, bool, Context &Ctx) {
991 if ( has_FlowTraits< SequenceTraits<T>>::value ) {
992 unsigned incnt = io.beginFlowSequence();
993 unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt;
994 for(unsigned i=0; i < count; ++i) {
995 void *SaveInfo;
996 if ( io.preflightFlowElement(i, SaveInfo) ) {
997 yamlize(io, SequenceTraits<T>::element(io, Seq, i), true, Ctx);
998 io.postflightFlowElement(SaveInfo);
999 }
1000 }
1001 io.endFlowSequence();
1002 }
1003 else {
1004 unsigned incnt = io.beginSequence();
1005 unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt;
1006 for(unsigned i=0; i < count; ++i) {
1007 void *SaveInfo;
1008 if ( io.preflightElement(i, SaveInfo) ) {
1009 yamlize(io, SequenceTraits<T>::element(io, Seq, i), true, Ctx);
1010 io.postflightElement(SaveInfo);
1011 }
1012 }
1013 io.endSequence();
1014 }
1015}
1016
1017template<>
1018struct ScalarTraits<bool> {
1019 static void output(const bool &, void* , raw_ostream &);
1020 static StringRef input(StringRef, void *, bool &);
1021 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1022};
1023
1024template<>
1025struct ScalarTraits<StringRef> {
1026 static void output(const StringRef &, void *, raw_ostream &);
1027 static StringRef input(StringRef, void *, StringRef &);
1028 static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
1029};
1030
1031template<>
1032struct ScalarTraits<std::string> {
1033 static void output(const std::string &, void *, raw_ostream &);
1034 static StringRef input(StringRef, void *, std::string &);
1035 static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
1036};
1037
1038template<>
1039struct ScalarTraits<uint8_t> {
1040 static void output(const uint8_t &, void *, raw_ostream &);
1041 static StringRef input(StringRef, void *, uint8_t &);
1042 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1043};
1044
1045template<>
1046struct ScalarTraits<uint16_t> {
1047 static void output(const uint16_t &, void *, raw_ostream &);
1048 static StringRef input(StringRef, void *, uint16_t &);
1049 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1050};
1051
1052template<>
1053struct ScalarTraits<uint32_t> {
1054 static void output(const uint32_t &, void *, raw_ostream &);
1055 static StringRef input(StringRef, void *, uint32_t &);
1056 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1057};
1058
1059template<>
1060struct ScalarTraits<uint64_t> {
1061 static void output(const uint64_t &, void *, raw_ostream &);
1062 static StringRef input(StringRef, void *, uint64_t &);
1063 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1064};
1065
1066template<>
1067struct ScalarTraits<int8_t> {
1068 static void output(const int8_t &, void *, raw_ostream &);
1069 static StringRef input(StringRef, void *, int8_t &);
1070 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1071};
1072
1073template<>
1074struct ScalarTraits<int16_t> {
1075 static void output(const int16_t &, void *, raw_ostream &);
1076 static StringRef input(StringRef, void *, int16_t &);
1077 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1078};
1079
1080template<>
1081struct ScalarTraits<int32_t> {
1082 static void output(const int32_t &, void *, raw_ostream &);
1083 static StringRef input(StringRef, void *, int32_t &);
1084 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1085};
1086
1087template<>
1088struct ScalarTraits<int64_t> {
1089 static void output(const int64_t &, void *, raw_ostream &);
1090 static StringRef input(StringRef, void *, int64_t &);
1091 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1092};
1093
1094template<>
1095struct ScalarTraits<float> {
1096 static void output(const float &, void *, raw_ostream &);
1097 static StringRef input(StringRef, void *, float &);
1098 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1099};
1100
1101template<>
1102struct ScalarTraits<double> {
1103 static void output(const double &, void *, raw_ostream &);
1104 static StringRef input(StringRef, void *, double &);
1105 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1106};
1107
1108// For endian types, we just use the existing ScalarTraits for the underlying
1109// type. This way endian aware types are supported whenever a ScalarTraits
1110// is defined for the underlying type.
1111template <typename value_type, support::endianness endian, size_t alignment>
1112struct ScalarTraits<support::detail::packed_endian_specific_integral<
1113 value_type, endian, alignment>> {
1114 using endian_type =
1115 support::detail::packed_endian_specific_integral<value_type, endian,
1116 alignment>;
1117
1118 static void output(const endian_type &E, void *Ctx, raw_ostream &Stream) {
1119 ScalarTraits<value_type>::output(static_cast<value_type>(E), Ctx, Stream);
1120 }
1121
1122 static StringRef input(StringRef Str, void *Ctx, endian_type &E) {
1123 value_type V;
1124 auto R = ScalarTraits<value_type>::input(Str, Ctx, V);
1125 E = static_cast<endian_type>(V);
1126 return R;
1127 }
1128
1129 static QuotingType mustQuote(StringRef Str) {
1130 return ScalarTraits<value_type>::mustQuote(Str);
1131 }
1132};
1133
1134// Utility for use within MappingTraits<>::mapping() method
1135// to [de]normalize an object for use with YAML conversion.
1136template <typename TNorm, typename TFinal>
1137struct MappingNormalization {
1138 MappingNormalization(IO &i_o, TFinal &Obj)
1139 : io(i_o), BufPtr(nullptr), Result(Obj) {
1140 if ( io.outputting() ) {
1141 BufPtr = new (&Buffer) TNorm(io, Obj);
1142 }
1143 else {
1144 BufPtr = new (&Buffer) TNorm(io);
1145 }
1146 }
1147
1148 ~MappingNormalization() {
1149 if ( ! io.outputting() ) {
1150 Result = BufPtr->denormalize(io);
1151 }
1152 BufPtr->~TNorm();
1153 }
1154
1155 TNorm* operator->() { return BufPtr; }
1156
1157private:
1158 using Storage = AlignedCharArrayUnion<TNorm>;
1159
1160 Storage Buffer;
1161 IO &io;
1162 TNorm *BufPtr;
1163 TFinal &Result;
1164};
1165
1166// Utility for use within MappingTraits<>::mapping() method
1167// to [de]normalize an object for use with YAML conversion.
1168template <typename TNorm, typename TFinal>
1169struct MappingNormalizationHeap {
1170 MappingNormalizationHeap(IO &i_o, TFinal &Obj, BumpPtrAllocator *allocator)
1171 : io(i_o), Result(Obj) {
1172 if ( io.outputting() ) {
1173 BufPtr = new (&Buffer) TNorm(io, Obj);
1174 }
1175 else if (allocator) {
1176 BufPtr = allocator->Allocate<TNorm>();
1177 new (BufPtr) TNorm(io);
1178 } else {
1179 BufPtr = new TNorm(io);
1180 }
1181 }
1182
1183 ~MappingNormalizationHeap() {
1184 if ( io.outputting() ) {
1185 BufPtr->~TNorm();
1186 }
1187 else {
1188 Result = BufPtr->denormalize(io);
1189 }
1190 }
1191
1192 TNorm* operator->() { return BufPtr; }
1193
1194private:
1195 using Storage = AlignedCharArrayUnion<TNorm>;
1196
1197 Storage Buffer;
1198 IO &io;
1199 TNorm *BufPtr = nullptr;
1200 TFinal &Result;
1201};
1202
1203///
1204/// The Input class is used to parse a yaml document into in-memory structs
1205/// and vectors.
1206///
1207/// It works by using YAMLParser to do a syntax parse of the entire yaml
1208/// document, then the Input class builds a graph of HNodes which wraps
1209/// each yaml Node. The extra layer is buffering. The low level yaml
1210/// parser only lets you look at each node once. The buffering layer lets
1211/// you search and interate multiple times. This is necessary because
1212/// the mapRequired() method calls may not be in the same order
1213/// as the keys in the document.
1214///
1215class Input : public IO {
1216public:
1217 // Construct a yaml Input object from a StringRef and optional
1218 // user-data. The DiagHandler can be specified to provide
1219 // alternative error reporting.
1220 Input(StringRef InputContent,
1221 void *Ctxt = nullptr,
1222 SourceMgr::DiagHandlerTy DiagHandler = nullptr,
1223 void *DiagHandlerCtxt = nullptr);
1224 Input(MemoryBufferRef Input,
1225 void *Ctxt = nullptr,
1226 SourceMgr::DiagHandlerTy DiagHandler = nullptr,
1227 void *DiagHandlerCtxt = nullptr);
1228 ~Input() override;
1229
1230 // Check if there was an syntax or semantic error during parsing.
1231 std::error_code error();
1232
1233private:
1234 bool outputting() override;
1235 bool mapTag(StringRef, bool) override;
1236 void beginMapping() override;
1237 void endMapping() override;
1238 bool preflightKey(const char *, bool, bool, bool &, void *&) override;
1239 void postflightKey(void *) override;
1240 std::vector<StringRef> keys() override;
1241 void beginFlowMapping() override;
1242 void endFlowMapping() override;
1243 unsigned beginSequence() override;
1244 void endSequence() override;
1245 bool preflightElement(unsigned index, void *&) override;
1246 void postflightElement(void *) override;
1247 unsigned beginFlowSequence() override;
1248 bool preflightFlowElement(unsigned , void *&) override;
1249 void postflightFlowElement(void *) override;
1250 void endFlowSequence() override;
1251 void beginEnumScalar() override;
1252 bool matchEnumScalar(const char*, bool) override;
1253 bool matchEnumFallback() override;
1254 void endEnumScalar() override;
1255 bool beginBitSetScalar(bool &) override;
1256 bool bitSetMatch(const char *, bool ) override;
1257 void endBitSetScalar() override;
1258 void scalarString(StringRef &, QuotingType) override;
1259 void blockScalarString(StringRef &) override;
1260 void setError(const Twine &message) override;
1261 bool canElideEmptySequence() override;
1262
1263 class HNode {
1264 virtual void anchor();
1265
1266 public:
1267 HNode(Node *n) : _node(n) { }
1268 virtual ~HNode() = default;
1269
1270 static bool classof(const HNode *) { return true; }
1271
1272 Node *_node;
1273 };
1274
1275 class EmptyHNode : public HNode {
1276 void anchor() override;
1277
1278 public:
1279 EmptyHNode(Node *n) : HNode(n) { }
1280
1281 static bool classof(const HNode *n) { return NullNode::classof(n->_node); }
1282
1283 static bool classof(const EmptyHNode *) { return true; }
1284 };
1285
1286 class ScalarHNode : public HNode {
1287 void anchor() override;
1288
1289 public:
1290 ScalarHNode(Node *n, StringRef s) : HNode(n), _value(s) { }
1291
1292 StringRef value() const { return _value; }
1293
1294 static bool classof(const HNode *n) {
1295 return ScalarNode::classof(n->_node) ||
1296 BlockScalarNode::classof(n->_node);
1297 }
1298
1299 static bool classof(const ScalarHNode *) { return true; }
1300
1301 protected:
1302 StringRef _value;
1303 };
1304
1305 class MapHNode : public HNode {
1306 void anchor() override;
1307
1308 public:
1309 MapHNode(Node *n) : HNode(n) { }
1310
1311 static bool classof(const HNode *n) {
1312 return MappingNode::classof(n->_node);
1313 }
1314
1315 static bool classof(const MapHNode *) { return true; }
1316
1317 using NameToNode = StringMap<std::unique_ptr<HNode>>;
1318
1319 NameToNode Mapping;
1320 SmallVector<std::string, 6> ValidKeys;
1321 };
1322
1323 class SequenceHNode : public HNode {
1324 void anchor() override;
1325
1326 public:
1327 SequenceHNode(Node *n) : HNode(n) { }
1328
1329 static bool classof(const HNode *n) {
1330 return SequenceNode::classof(n->_node);
1331 }
1332
1333 static bool classof(const SequenceHNode *) { return true; }
1334
1335 std::vector<std::unique_ptr<HNode>> Entries;
1336 };
1337
1338 std::unique_ptr<Input::HNode> createHNodes(Node *node);
1339 void setError(HNode *hnode, const Twine &message);
1340 void setError(Node *node, const Twine &message);
1341
1342public:
1343 // These are only used by operator>>. They could be private
1344 // if those templated things could be made friends.
1345 bool setCurrentDocument();
1346 bool nextDocument();
1347
1348 /// Returns the current node that's being parsed by the YAML Parser.
1349 const Node *getCurrentNode() const;
1350
1351private:
1352 SourceMgr SrcMgr; // must be before Strm
1353 std::unique_ptr<llvm::yaml::Stream> Strm;
1354 std::unique_ptr<HNode> TopNode;
1355 std::error_code EC;
1356 BumpPtrAllocator StringAllocator;
1357 document_iterator DocIterator;
1358 std::vector<bool> BitValuesUsed;
1359 HNode *CurrentNode = nullptr;
1360 bool ScalarMatchFound;
1361};
1362
1363///
1364/// The Output class is used to generate a yaml document from in-memory structs
1365/// and vectors.
1366///
1367class Output : public IO {
1368public:
1369 Output(raw_ostream &, void *Ctxt = nullptr, int WrapColumn = 70);
1370 ~Output() override;
1371
Andrew Scullcdfcccc2018-10-05 20:58:37 +01001372 /// Set whether or not to output optional values which are equal
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001373 /// to the default value. By default, when outputting if you attempt
1374 /// to write a value that is equal to the default, the value gets ignored.
1375 /// Sometimes, it is useful to be able to see these in the resulting YAML
1376 /// anyway.
1377 void setWriteDefaultValues(bool Write) { WriteDefaultValues = Write; }
1378
1379 bool outputting() override;
1380 bool mapTag(StringRef, bool) override;
1381 void beginMapping() override;
1382 void endMapping() override;
1383 bool preflightKey(const char *key, bool, bool, bool &, void *&) override;
1384 void postflightKey(void *) override;
1385 std::vector<StringRef> keys() override;
1386 void beginFlowMapping() override;
1387 void endFlowMapping() override;
1388 unsigned beginSequence() override;
1389 void endSequence() override;
1390 bool preflightElement(unsigned, void *&) override;
1391 void postflightElement(void *) override;
1392 unsigned beginFlowSequence() override;
1393 bool preflightFlowElement(unsigned, void *&) override;
1394 void postflightFlowElement(void *) override;
1395 void endFlowSequence() override;
1396 void beginEnumScalar() override;
1397 bool matchEnumScalar(const char*, bool) override;
1398 bool matchEnumFallback() override;
1399 void endEnumScalar() override;
1400 bool beginBitSetScalar(bool &) override;
1401 bool bitSetMatch(const char *, bool ) override;
1402 void endBitSetScalar() override;
1403 void scalarString(StringRef &, QuotingType) override;
1404 void blockScalarString(StringRef &) override;
1405 void setError(const Twine &message) override;
1406 bool canElideEmptySequence() override;
1407
1408 // These are only used by operator<<. They could be private
1409 // if that templated operator could be made a friend.
1410 void beginDocuments();
1411 bool preflightDocument(unsigned);
1412 void postflightDocument();
1413 void endDocuments();
1414
1415private:
1416 void output(StringRef s);
1417 void outputUpToEndOfLine(StringRef s);
1418 void newLineCheck();
1419 void outputNewLine();
1420 void paddedKey(StringRef key);
1421 void flowKey(StringRef Key);
1422
1423 enum InState {
1424 inSeq,
1425 inFlowSeq,
1426 inMapFirstKey,
1427 inMapOtherKey,
1428 inFlowMapFirstKey,
1429 inFlowMapOtherKey
1430 };
1431
1432 raw_ostream &Out;
1433 int WrapColumn;
1434 SmallVector<InState, 8> StateStack;
1435 int Column = 0;
1436 int ColumnAtFlowStart = 0;
1437 int ColumnAtMapFlowStart = 0;
1438 bool NeedBitValueComma = false;
1439 bool NeedFlowSequenceComma = false;
1440 bool EnumerationMatchFound = false;
1441 bool NeedsNewLine = false;
1442 bool WriteDefaultValues = false;
1443};
1444
1445/// YAML I/O does conversion based on types. But often native data types
1446/// are just a typedef of built in intergral types (e.g. int). But the C++
1447/// type matching system sees through the typedef and all the typedefed types
1448/// look like a built in type. This will cause the generic YAML I/O conversion
1449/// to be used. To provide better control over the YAML conversion, you can
1450/// use this macro instead of typedef. It will create a class with one field
1451/// and automatic conversion operators to and from the base type.
1452/// Based on BOOST_STRONG_TYPEDEF
1453#define LLVM_YAML_STRONG_TYPEDEF(_base, _type) \
1454 struct _type { \
1455 _type() = default; \
1456 _type(const _base v) : value(v) {} \
1457 _type(const _type &v) = default; \
1458 _type &operator=(const _type &rhs) = default; \
1459 _type &operator=(const _base &rhs) { value = rhs; return *this; } \
1460 operator const _base & () const { return value; } \
1461 bool operator==(const _type &rhs) const { return value == rhs.value; } \
1462 bool operator==(const _base &rhs) const { return value == rhs; } \
1463 bool operator<(const _type &rhs) const { return value < rhs.value; } \
1464 _base value; \
1465 using BaseType = _base; \
1466 };
1467
1468///
1469/// Use these types instead of uintXX_t in any mapping to have
1470/// its yaml output formatted as hexadecimal.
1471///
1472LLVM_YAML_STRONG_TYPEDEF(uint8_t, Hex8)
1473LLVM_YAML_STRONG_TYPEDEF(uint16_t, Hex16)
1474LLVM_YAML_STRONG_TYPEDEF(uint32_t, Hex32)
1475LLVM_YAML_STRONG_TYPEDEF(uint64_t, Hex64)
1476
1477template<>
1478struct ScalarTraits<Hex8> {
1479 static void output(const Hex8 &, void *, raw_ostream &);
1480 static StringRef input(StringRef, void *, Hex8 &);
1481 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1482};
1483
1484template<>
1485struct ScalarTraits<Hex16> {
1486 static void output(const Hex16 &, void *, raw_ostream &);
1487 static StringRef input(StringRef, void *, Hex16 &);
1488 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1489};
1490
1491template<>
1492struct ScalarTraits<Hex32> {
1493 static void output(const Hex32 &, void *, raw_ostream &);
1494 static StringRef input(StringRef, void *, Hex32 &);
1495 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1496};
1497
1498template<>
1499struct ScalarTraits<Hex64> {
1500 static void output(const Hex64 &, void *, raw_ostream &);
1501 static StringRef input(StringRef, void *, Hex64 &);
1502 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
1503};
1504
1505// Define non-member operator>> so that Input can stream in a document list.
1506template <typename T>
1507inline
1508typename std::enable_if<has_DocumentListTraits<T>::value, Input &>::type
1509operator>>(Input &yin, T &docList) {
1510 int i = 0;
1511 EmptyContext Ctx;
1512 while ( yin.setCurrentDocument() ) {
1513 yamlize(yin, DocumentListTraits<T>::element(yin, docList, i), true, Ctx);
1514 if ( yin.error() )
1515 return yin;
1516 yin.nextDocument();
1517 ++i;
1518 }
1519 return yin;
1520}
1521
1522// Define non-member operator>> so that Input can stream in a map as a document.
1523template <typename T>
1524inline typename std::enable_if<has_MappingTraits<T, EmptyContext>::value,
1525 Input &>::type
1526operator>>(Input &yin, T &docMap) {
1527 EmptyContext Ctx;
1528 yin.setCurrentDocument();
1529 yamlize(yin, docMap, true, Ctx);
1530 return yin;
1531}
1532
1533// Define non-member operator>> so that Input can stream in a sequence as
1534// a document.
1535template <typename T>
1536inline
1537typename std::enable_if<has_SequenceTraits<T>::value, Input &>::type
1538operator>>(Input &yin, T &docSeq) {
1539 EmptyContext Ctx;
1540 if (yin.setCurrentDocument())
1541 yamlize(yin, docSeq, true, Ctx);
1542 return yin;
1543}
1544
1545// Define non-member operator>> so that Input can stream in a block scalar.
1546template <typename T>
1547inline
1548typename std::enable_if<has_BlockScalarTraits<T>::value, Input &>::type
1549operator>>(Input &In, T &Val) {
1550 EmptyContext Ctx;
1551 if (In.setCurrentDocument())
1552 yamlize(In, Val, true, Ctx);
1553 return In;
1554}
1555
1556// Define non-member operator>> so that Input can stream in a string map.
1557template <typename T>
1558inline
1559typename std::enable_if<has_CustomMappingTraits<T>::value, Input &>::type
1560operator>>(Input &In, T &Val) {
1561 EmptyContext Ctx;
1562 if (In.setCurrentDocument())
1563 yamlize(In, Val, true, Ctx);
1564 return In;
1565}
1566
1567// Provide better error message about types missing a trait specialization
1568template <typename T>
1569inline typename std::enable_if<missingTraits<T, EmptyContext>::value,
1570 Input &>::type
1571operator>>(Input &yin, T &docSeq) {
1572 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
1573 return yin;
1574}
1575
1576// Define non-member operator<< so that Output can stream out document list.
1577template <typename T>
1578inline
1579typename std::enable_if<has_DocumentListTraits<T>::value, Output &>::type
1580operator<<(Output &yout, T &docList) {
1581 EmptyContext Ctx;
1582 yout.beginDocuments();
1583 const size_t count = DocumentListTraits<T>::size(yout, docList);
1584 for(size_t i=0; i < count; ++i) {
1585 if ( yout.preflightDocument(i) ) {
1586 yamlize(yout, DocumentListTraits<T>::element(yout, docList, i), true,
1587 Ctx);
1588 yout.postflightDocument();
1589 }
1590 }
1591 yout.endDocuments();
1592 return yout;
1593}
1594
1595// Define non-member operator<< so that Output can stream out a map.
1596template <typename T>
1597inline typename std::enable_if<has_MappingTraits<T, EmptyContext>::value,
1598 Output &>::type
1599operator<<(Output &yout, T &map) {
1600 EmptyContext Ctx;
1601 yout.beginDocuments();
1602 if ( yout.preflightDocument(0) ) {
1603 yamlize(yout, map, true, Ctx);
1604 yout.postflightDocument();
1605 }
1606 yout.endDocuments();
1607 return yout;
1608}
1609
1610// Define non-member operator<< so that Output can stream out a sequence.
1611template <typename T>
1612inline
1613typename std::enable_if<has_SequenceTraits<T>::value, Output &>::type
1614operator<<(Output &yout, T &seq) {
1615 EmptyContext Ctx;
1616 yout.beginDocuments();
1617 if ( yout.preflightDocument(0) ) {
1618 yamlize(yout, seq, true, Ctx);
1619 yout.postflightDocument();
1620 }
1621 yout.endDocuments();
1622 return yout;
1623}
1624
1625// Define non-member operator<< so that Output can stream out a block scalar.
1626template <typename T>
1627inline
1628typename std::enable_if<has_BlockScalarTraits<T>::value, Output &>::type
1629operator<<(Output &Out, T &Val) {
1630 EmptyContext Ctx;
1631 Out.beginDocuments();
1632 if (Out.preflightDocument(0)) {
1633 yamlize(Out, Val, true, Ctx);
1634 Out.postflightDocument();
1635 }
1636 Out.endDocuments();
1637 return Out;
1638}
1639
1640// Define non-member operator<< so that Output can stream out a string map.
1641template <typename T>
1642inline
1643typename std::enable_if<has_CustomMappingTraits<T>::value, Output &>::type
1644operator<<(Output &Out, T &Val) {
1645 EmptyContext Ctx;
1646 Out.beginDocuments();
1647 if (Out.preflightDocument(0)) {
1648 yamlize(Out, Val, true, Ctx);
1649 Out.postflightDocument();
1650 }
1651 Out.endDocuments();
1652 return Out;
1653}
1654
1655// Provide better error message about types missing a trait specialization
1656template <typename T>
1657inline typename std::enable_if<missingTraits<T, EmptyContext>::value,
1658 Output &>::type
1659operator<<(Output &yout, T &seq) {
1660 char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
1661 return yout;
1662}
1663
1664template <bool B> struct IsFlowSequenceBase {};
1665template <> struct IsFlowSequenceBase<true> { static const bool flow = true; };
1666
1667template <typename T, bool Flow>
1668struct SequenceTraitsImpl : IsFlowSequenceBase<Flow> {
1669private:
1670 using type = typename T::value_type;
1671
1672public:
1673 static size_t size(IO &io, T &seq) { return seq.size(); }
1674
1675 static type &element(IO &io, T &seq, size_t index) {
1676 if (index >= seq.size())
1677 seq.resize(index + 1);
1678 return seq[index];
1679 }
1680};
1681
1682// Simple helper to check an expression can be used as a bool-valued template
1683// argument.
1684template <bool> struct CheckIsBool { static const bool value = true; };
1685
1686// If T has SequenceElementTraits, then vector<T> and SmallVector<T, N> have
1687// SequenceTraits that do the obvious thing.
1688template <typename T>
1689struct SequenceTraits<std::vector<T>,
1690 typename std::enable_if<CheckIsBool<
1691 SequenceElementTraits<T>::flow>::value>::type>
1692 : SequenceTraitsImpl<std::vector<T>, SequenceElementTraits<T>::flow> {};
1693template <typename T, unsigned N>
1694struct SequenceTraits<SmallVector<T, N>,
1695 typename std::enable_if<CheckIsBool<
1696 SequenceElementTraits<T>::flow>::value>::type>
1697 : SequenceTraitsImpl<SmallVector<T, N>, SequenceElementTraits<T>::flow> {};
1698
1699// Sequences of fundamental types use flow formatting.
1700template <typename T>
1701struct SequenceElementTraits<
1702 T, typename std::enable_if<std::is_fundamental<T>::value>::type> {
1703 static const bool flow = true;
1704};
1705
1706// Sequences of strings use block formatting.
1707template<> struct SequenceElementTraits<std::string> {
1708 static const bool flow = false;
1709};
1710template<> struct SequenceElementTraits<StringRef> {
1711 static const bool flow = false;
1712};
1713template<> struct SequenceElementTraits<std::pair<std::string, std::string>> {
1714 static const bool flow = false;
1715};
1716
1717/// Implementation of CustomMappingTraits for std::map<std::string, T>.
1718template <typename T> struct StdMapStringCustomMappingTraitsImpl {
1719 using map_type = std::map<std::string, T>;
1720
1721 static void inputOne(IO &io, StringRef key, map_type &v) {
1722 io.mapRequired(key.str().c_str(), v[key]);
1723 }
1724
1725 static void output(IO &io, map_type &v) {
1726 for (auto &p : v)
1727 io.mapRequired(p.first.c_str(), p.second);
1728 }
1729};
1730
1731} // end namespace yaml
1732} // end namespace llvm
1733
1734#define LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(TYPE, FLOW) \
1735 namespace llvm { \
1736 namespace yaml { \
1737 static_assert( \
1738 !std::is_fundamental<TYPE>::value && \
1739 !std::is_same<TYPE, std::string>::value && \
1740 !std::is_same<TYPE, llvm::StringRef>::value, \
1741 "only use LLVM_YAML_IS_SEQUENCE_VECTOR for types you control"); \
1742 template <> struct SequenceElementTraits<TYPE> { \
1743 static const bool flow = FLOW; \
1744 }; \
1745 } \
1746 }
1747
1748/// Utility for declaring that a std::vector of a particular type
1749/// should be considered a YAML sequence.
1750#define LLVM_YAML_IS_SEQUENCE_VECTOR(type) \
1751 LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(type, false)
1752
1753/// Utility for declaring that a std::vector of a particular type
1754/// should be considered a YAML flow sequence.
1755#define LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(type) \
1756 LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(type, true)
1757
1758#define LLVM_YAML_DECLARE_MAPPING_TRAITS(Type) \
1759 namespace llvm { \
1760 namespace yaml { \
1761 template <> struct MappingTraits<Type> { \
1762 static void mapping(IO &IO, Type &Obj); \
1763 }; \
1764 } \
1765 }
1766
1767#define LLVM_YAML_DECLARE_ENUM_TRAITS(Type) \
1768 namespace llvm { \
1769 namespace yaml { \
1770 template <> struct ScalarEnumerationTraits<Type> { \
1771 static void enumeration(IO &io, Type &Value); \
1772 }; \
1773 } \
1774 }
1775
1776#define LLVM_YAML_DECLARE_BITSET_TRAITS(Type) \
1777 namespace llvm { \
1778 namespace yaml { \
1779 template <> struct ScalarBitSetTraits<Type> { \
1780 static void bitset(IO &IO, Type &Options); \
1781 }; \
1782 } \
1783 }
1784
1785#define LLVM_YAML_DECLARE_SCALAR_TRAITS(Type, MustQuote) \
1786 namespace llvm { \
1787 namespace yaml { \
1788 template <> struct ScalarTraits<Type> { \
1789 static void output(const Type &Value, void *ctx, raw_ostream &Out); \
1790 static StringRef input(StringRef Scalar, void *ctxt, Type &Value); \
1791 static QuotingType mustQuote(StringRef) { return MustQuote; } \
1792 }; \
1793 } \
1794 }
1795
1796/// Utility for declaring that a std::vector of a particular type
1797/// should be considered a YAML document list.
1798#define LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(_type) \
1799 namespace llvm { \
1800 namespace yaml { \
1801 template <unsigned N> \
1802 struct DocumentListTraits<SmallVector<_type, N>> \
1803 : public SequenceTraitsImpl<SmallVector<_type, N>, false> {}; \
1804 template <> \
1805 struct DocumentListTraits<std::vector<_type>> \
1806 : public SequenceTraitsImpl<std::vector<_type>, false> {}; \
1807 } \
1808 }
1809
1810/// Utility for declaring that std::map<std::string, _type> should be considered
1811/// a YAML map.
1812#define LLVM_YAML_IS_STRING_MAP(_type) \
1813 namespace llvm { \
1814 namespace yaml { \
1815 template <> \
1816 struct CustomMappingTraits<std::map<std::string, _type>> \
1817 : public StdMapStringCustomMappingTraitsImpl<_type> {}; \
1818 } \
1819 }
1820
1821#endif // LLVM_SUPPORT_YAMLTRAITS_H