xref: /netbsd-src/external/apache2/llvm/dist/llvm/docs/YamlIO.rst (revision 82d56013d7b633d116a93943de88e08335357a7c)
17330f729Sjoerg=====================
27330f729SjoergYAML I/O
37330f729Sjoerg=====================
47330f729Sjoerg
57330f729Sjoerg.. contents::
67330f729Sjoerg   :local:
77330f729Sjoerg
87330f729SjoergIntroduction to YAML
97330f729Sjoerg====================
107330f729Sjoerg
117330f729SjoergYAML is a human readable data serialization language.  The full YAML language
127330f729Sjoergspec can be read at `yaml.org
137330f729Sjoerg<http://www.yaml.org/spec/1.2/spec.html#Introduction>`_.  The simplest form of
147330f729Sjoergyaml is just "scalars", "mappings", and "sequences".  A scalar is any number
157330f729Sjoergor string.  The pound/hash symbol (#) begins a comment line.   A mapping is
167330f729Sjoerga set of key-value pairs where the key ends with a colon.  For example:
177330f729Sjoerg
187330f729Sjoerg.. code-block:: yaml
197330f729Sjoerg
207330f729Sjoerg     # a mapping
217330f729Sjoerg     name:      Tom
227330f729Sjoerg     hat-size:  7
237330f729Sjoerg
247330f729SjoergA sequence is a list of items where each item starts with a leading dash ('-').
257330f729SjoergFor example:
267330f729Sjoerg
277330f729Sjoerg.. code-block:: yaml
287330f729Sjoerg
297330f729Sjoerg     # a sequence
307330f729Sjoerg     - x86
317330f729Sjoerg     - x86_64
327330f729Sjoerg     - PowerPC
337330f729Sjoerg
347330f729SjoergYou can combine mappings and sequences by indenting.  For example a sequence
357330f729Sjoergof mappings in which one of the mapping values is itself a sequence:
367330f729Sjoerg
377330f729Sjoerg.. code-block:: yaml
387330f729Sjoerg
397330f729Sjoerg     # a sequence of mappings with one key's value being a sequence
407330f729Sjoerg     - name:      Tom
417330f729Sjoerg       cpus:
427330f729Sjoerg        - x86
437330f729Sjoerg        - x86_64
447330f729Sjoerg     - name:      Bob
457330f729Sjoerg       cpus:
467330f729Sjoerg        - x86
477330f729Sjoerg     - name:      Dan
487330f729Sjoerg       cpus:
497330f729Sjoerg        - PowerPC
507330f729Sjoerg        - x86
517330f729Sjoerg
527330f729SjoergSometime sequences are known to be short and the one entry per line is too
537330f729Sjoergverbose, so YAML offers an alternate syntax for sequences called a "Flow
547330f729SjoergSequence" in which you put comma separated sequence elements into square
557330f729Sjoergbrackets.  The above example could then be simplified to :
567330f729Sjoerg
577330f729Sjoerg
587330f729Sjoerg.. code-block:: yaml
597330f729Sjoerg
607330f729Sjoerg     # a sequence of mappings with one key's value being a flow sequence
617330f729Sjoerg     - name:      Tom
627330f729Sjoerg       cpus:      [ x86, x86_64 ]
637330f729Sjoerg     - name:      Bob
647330f729Sjoerg       cpus:      [ x86 ]
657330f729Sjoerg     - name:      Dan
667330f729Sjoerg       cpus:      [ PowerPC, x86 ]
677330f729Sjoerg
687330f729Sjoerg
697330f729SjoergIntroduction to YAML I/O
707330f729Sjoerg========================
717330f729Sjoerg
727330f729SjoergThe use of indenting makes the YAML easy for a human to read and understand,
737330f729Sjoergbut having a program read and write YAML involves a lot of tedious details.
747330f729SjoergThe YAML I/O library structures and simplifies reading and writing YAML
757330f729Sjoergdocuments.
767330f729Sjoerg
777330f729SjoergYAML I/O assumes you have some "native" data structures which you want to be
787330f729Sjoergable to dump as YAML and recreate from YAML.  The first step is to try
797330f729Sjoergwriting example YAML for your data structures. You may find after looking at
807330f729Sjoergpossible YAML representations that a direct mapping of your data structures
817330f729Sjoergto YAML is not very readable.  Often the fields are not in the order that
827330f729Sjoerga human would find readable.  Or the same information is replicated in multiple
837330f729Sjoerglocations, making it hard for a human to write such YAML correctly.
847330f729Sjoerg
857330f729SjoergIn relational database theory there is a design step called normalization in
867330f729Sjoergwhich you reorganize fields and tables.  The same considerations need to
877330f729Sjoerggo into the design of your YAML encoding.  But, you may not want to change
887330f729Sjoergyour existing native data structures.  Therefore, when writing out YAML
897330f729Sjoergthere may be a normalization step, and when reading YAML there would be a
907330f729Sjoergcorresponding denormalization step.
917330f729Sjoerg
927330f729SjoergYAML I/O uses a non-invasive, traits based design.  YAML I/O defines some
937330f729Sjoergabstract base templates.  You specialize those templates on your data types.
947330f729SjoergFor instance, if you have an enumerated type FooBar you could specialize
957330f729SjoergScalarEnumerationTraits on that type and define the enumeration() method:
967330f729Sjoerg
977330f729Sjoerg.. code-block:: c++
987330f729Sjoerg
997330f729Sjoerg    using llvm::yaml::ScalarEnumerationTraits;
1007330f729Sjoerg    using llvm::yaml::IO;
1017330f729Sjoerg
1027330f729Sjoerg    template <>
1037330f729Sjoerg    struct ScalarEnumerationTraits<FooBar> {
1047330f729Sjoerg      static void enumeration(IO &io, FooBar &value) {
1057330f729Sjoerg      ...
1067330f729Sjoerg      }
1077330f729Sjoerg    };
1087330f729Sjoerg
1097330f729Sjoerg
1107330f729SjoergAs with all YAML I/O template specializations, the ScalarEnumerationTraits is used for
1117330f729Sjoergboth reading and writing YAML. That is, the mapping between in-memory enum
1127330f729Sjoergvalues and the YAML string representation is only in one place.
1137330f729SjoergThis assures that the code for writing and parsing of YAML stays in sync.
1147330f729Sjoerg
1157330f729SjoergTo specify a YAML mappings, you define a specialization on
1167330f729Sjoergllvm::yaml::MappingTraits.
1177330f729SjoergIf your native data structure happens to be a struct that is already normalized,
1187330f729Sjoergthen the specialization is simple.  For example:
1197330f729Sjoerg
1207330f729Sjoerg.. code-block:: c++
1217330f729Sjoerg
1227330f729Sjoerg    using llvm::yaml::MappingTraits;
1237330f729Sjoerg    using llvm::yaml::IO;
1247330f729Sjoerg
1257330f729Sjoerg    template <>
1267330f729Sjoerg    struct MappingTraits<Person> {
1277330f729Sjoerg      static void mapping(IO &io, Person &info) {
1287330f729Sjoerg        io.mapRequired("name",         info.name);
1297330f729Sjoerg        io.mapOptional("hat-size",     info.hatSize);
1307330f729Sjoerg      }
1317330f729Sjoerg    };
1327330f729Sjoerg
1337330f729Sjoerg
1347330f729SjoergA YAML sequence is automatically inferred if you data type has begin()/end()
1357330f729Sjoergiterators and a push_back() method.  Therefore any of the STL containers
1367330f729Sjoerg(such as std::vector<>) will automatically translate to YAML sequences.
1377330f729Sjoerg
1387330f729SjoergOnce you have defined specializations for your data types, you can
1397330f729Sjoergprogrammatically use YAML I/O to write a YAML document:
1407330f729Sjoerg
1417330f729Sjoerg.. code-block:: c++
1427330f729Sjoerg
1437330f729Sjoerg    using llvm::yaml::Output;
1447330f729Sjoerg
1457330f729Sjoerg    Person tom;
1467330f729Sjoerg    tom.name = "Tom";
1477330f729Sjoerg    tom.hatSize = 8;
1487330f729Sjoerg    Person dan;
1497330f729Sjoerg    dan.name = "Dan";
1507330f729Sjoerg    dan.hatSize = 7;
1517330f729Sjoerg    std::vector<Person> persons;
1527330f729Sjoerg    persons.push_back(tom);
1537330f729Sjoerg    persons.push_back(dan);
1547330f729Sjoerg
1557330f729Sjoerg    Output yout(llvm::outs());
1567330f729Sjoerg    yout << persons;
1577330f729Sjoerg
1587330f729SjoergThis would write the following:
1597330f729Sjoerg
1607330f729Sjoerg.. code-block:: yaml
1617330f729Sjoerg
1627330f729Sjoerg     - name:      Tom
1637330f729Sjoerg       hat-size:  8
1647330f729Sjoerg     - name:      Dan
1657330f729Sjoerg       hat-size:  7
1667330f729Sjoerg
1677330f729SjoergAnd you can also read such YAML documents with the following code:
1687330f729Sjoerg
1697330f729Sjoerg.. code-block:: c++
1707330f729Sjoerg
1717330f729Sjoerg    using llvm::yaml::Input;
1727330f729Sjoerg
1737330f729Sjoerg    typedef std::vector<Person> PersonList;
1747330f729Sjoerg    std::vector<PersonList> docs;
1757330f729Sjoerg
1767330f729Sjoerg    Input yin(document.getBuffer());
1777330f729Sjoerg    yin >> docs;
1787330f729Sjoerg
1797330f729Sjoerg    if ( yin.error() )
1807330f729Sjoerg      return;
1817330f729Sjoerg
1827330f729Sjoerg    // Process read document
1837330f729Sjoerg    for ( PersonList &pl : docs ) {
1847330f729Sjoerg      for ( Person &person : pl ) {
1857330f729Sjoerg        cout << "name=" << person.name;
1867330f729Sjoerg      }
1877330f729Sjoerg    }
1887330f729Sjoerg
1897330f729SjoergOne other feature of YAML is the ability to define multiple documents in a
1907330f729Sjoergsingle file.  That is why reading YAML produces a vector of your document type.
1917330f729Sjoerg
1927330f729Sjoerg
1937330f729Sjoerg
1947330f729SjoergError Handling
1957330f729Sjoerg==============
1967330f729Sjoerg
1977330f729SjoergWhen parsing a YAML document, if the input does not match your schema (as
1987330f729Sjoergexpressed in your XxxTraits<> specializations).  YAML I/O
1997330f729Sjoergwill print out an error message and your Input object's error() method will
2007330f729Sjoergreturn true. For instance the following document:
2017330f729Sjoerg
2027330f729Sjoerg.. code-block:: yaml
2037330f729Sjoerg
2047330f729Sjoerg     - name:      Tom
2057330f729Sjoerg       shoe-size: 12
2067330f729Sjoerg     - name:      Dan
2077330f729Sjoerg       hat-size:  7
2087330f729Sjoerg
2097330f729SjoergHas a key (shoe-size) that is not defined in the schema.  YAML I/O will
2107330f729Sjoergautomatically generate this error:
2117330f729Sjoerg
2127330f729Sjoerg.. code-block:: yaml
2137330f729Sjoerg
2147330f729Sjoerg    YAML:2:2: error: unknown key 'shoe-size'
2157330f729Sjoerg      shoe-size:       12
2167330f729Sjoerg      ^~~~~~~~~
2177330f729Sjoerg
2187330f729SjoergSimilar errors are produced for other input not conforming to the schema.
2197330f729Sjoerg
2207330f729Sjoerg
2217330f729SjoergScalars
2227330f729Sjoerg=======
2237330f729Sjoerg
2247330f729SjoergYAML scalars are just strings (i.e. not a sequence or mapping).  The YAML I/O
2257330f729Sjoerglibrary provides support for translating between YAML scalars and specific
2267330f729SjoergC++ types.
2277330f729Sjoerg
2287330f729Sjoerg
2297330f729SjoergBuilt-in types
2307330f729Sjoerg--------------
2317330f729SjoergThe following types have built-in support in YAML I/O:
2327330f729Sjoerg
2337330f729Sjoerg* bool
2347330f729Sjoerg* float
2357330f729Sjoerg* double
2367330f729Sjoerg* StringRef
2377330f729Sjoerg* std::string
2387330f729Sjoerg* int64_t
2397330f729Sjoerg* int32_t
2407330f729Sjoerg* int16_t
2417330f729Sjoerg* int8_t
2427330f729Sjoerg* uint64_t
2437330f729Sjoerg* uint32_t
2447330f729Sjoerg* uint16_t
2457330f729Sjoerg* uint8_t
2467330f729Sjoerg
2477330f729SjoergThat is, you can use those types in fields of MappingTraits or as element type
2487330f729Sjoergin sequence.  When reading, YAML I/O will validate that the string found
2497330f729Sjoergis convertible to that type and error out if not.
2507330f729Sjoerg
2517330f729Sjoerg
2527330f729SjoergUnique types
2537330f729Sjoerg------------
2547330f729SjoergGiven that YAML I/O is trait based, the selection of how to convert your data
2557330f729Sjoergto YAML is based on the type of your data.  But in C++ type matching, typedefs
2567330f729Sjoergdo not generate unique type names.  That means if you have two typedefs of
2577330f729Sjoergunsigned int, to YAML I/O both types look exactly like unsigned int.  To
2587330f729Sjoergfacilitate make unique type names, YAML I/O provides a macro which is used
2597330f729Sjoerglike a typedef on built-in types, but expands to create a class with conversion
2607330f729Sjoergoperators to and from the base type.  For example:
2617330f729Sjoerg
2627330f729Sjoerg.. code-block:: c++
2637330f729Sjoerg
2647330f729Sjoerg    LLVM_YAML_STRONG_TYPEDEF(uint32_t, MyFooFlags)
2657330f729Sjoerg    LLVM_YAML_STRONG_TYPEDEF(uint32_t, MyBarFlags)
2667330f729Sjoerg
2677330f729SjoergThis generates two classes MyFooFlags and MyBarFlags which you can use in your
2687330f729Sjoergnative data structures instead of uint32_t. They are implicitly
2697330f729Sjoergconverted to and from uint32_t.  The point of creating these unique types
2707330f729Sjoergis that you can now specify traits on them to get different YAML conversions.
2717330f729Sjoerg
2727330f729SjoergHex types
2737330f729Sjoerg---------
2747330f729SjoergAn example use of a unique type is that YAML I/O provides fixed sized unsigned
2757330f729Sjoergintegers that are written with YAML I/O as hexadecimal instead of the decimal
2767330f729Sjoergformat used by the built-in integer types:
2777330f729Sjoerg
2787330f729Sjoerg* Hex64
2797330f729Sjoerg* Hex32
2807330f729Sjoerg* Hex16
2817330f729Sjoerg* Hex8
2827330f729Sjoerg
2837330f729SjoergYou can use llvm::yaml::Hex32 instead of uint32_t and the only different will
2847330f729Sjoergbe that when YAML I/O writes out that type it will be formatted in hexadecimal.
2857330f729Sjoerg
2867330f729Sjoerg
2877330f729SjoergScalarEnumerationTraits
2887330f729Sjoerg-----------------------
2897330f729SjoergYAML I/O supports translating between in-memory enumerations and a set of string
2907330f729Sjoergvalues in YAML documents. This is done by specializing ScalarEnumerationTraits<>
291*82d56013Sjoergon your enumeration type and define an enumeration() method.
2927330f729SjoergFor instance, suppose you had an enumeration of CPUs and a struct with it as
2937330f729Sjoerga field:
2947330f729Sjoerg
2957330f729Sjoerg.. code-block:: c++
2967330f729Sjoerg
2977330f729Sjoerg    enum CPUs {
2987330f729Sjoerg      cpu_x86_64  = 5,
2997330f729Sjoerg      cpu_x86     = 7,
3007330f729Sjoerg      cpu_PowerPC = 8
3017330f729Sjoerg    };
3027330f729Sjoerg
3037330f729Sjoerg    struct Info {
3047330f729Sjoerg      CPUs      cpu;
3057330f729Sjoerg      uint32_t  flags;
3067330f729Sjoerg    };
3077330f729Sjoerg
3087330f729SjoergTo support reading and writing of this enumeration, you can define a
3097330f729SjoergScalarEnumerationTraits specialization on CPUs, which can then be used
3107330f729Sjoergas a field type:
3117330f729Sjoerg
3127330f729Sjoerg.. code-block:: c++
3137330f729Sjoerg
3147330f729Sjoerg    using llvm::yaml::ScalarEnumerationTraits;
3157330f729Sjoerg    using llvm::yaml::MappingTraits;
3167330f729Sjoerg    using llvm::yaml::IO;
3177330f729Sjoerg
3187330f729Sjoerg    template <>
3197330f729Sjoerg    struct ScalarEnumerationTraits<CPUs> {
3207330f729Sjoerg      static void enumeration(IO &io, CPUs &value) {
3217330f729Sjoerg        io.enumCase(value, "x86_64",  cpu_x86_64);
3227330f729Sjoerg        io.enumCase(value, "x86",     cpu_x86);
3237330f729Sjoerg        io.enumCase(value, "PowerPC", cpu_PowerPC);
3247330f729Sjoerg      }
3257330f729Sjoerg    };
3267330f729Sjoerg
3277330f729Sjoerg    template <>
3287330f729Sjoerg    struct MappingTraits<Info> {
3297330f729Sjoerg      static void mapping(IO &io, Info &info) {
3307330f729Sjoerg        io.mapRequired("cpu",       info.cpu);
3317330f729Sjoerg        io.mapOptional("flags",     info.flags, 0);
3327330f729Sjoerg      }
3337330f729Sjoerg    };
3347330f729Sjoerg
3357330f729SjoergWhen reading YAML, if the string found does not match any of the strings
3367330f729Sjoergspecified by enumCase() methods, an error is automatically generated.
3377330f729SjoergWhen writing YAML, if the value being written does not match any of the values
3387330f729Sjoergspecified by the enumCase() methods, a runtime assertion is triggered.
3397330f729Sjoerg
3407330f729Sjoerg
3417330f729SjoergBitValue
3427330f729Sjoerg--------
3437330f729SjoergAnother common data structure in C++ is a field where each bit has a unique
3447330f729Sjoergmeaning.  This is often used in a "flags" field.  YAML I/O has support for
3457330f729Sjoergconverting such fields to a flow sequence.   For instance suppose you
3467330f729Sjoerghad the following bit flags defined:
3477330f729Sjoerg
3487330f729Sjoerg.. code-block:: c++
3497330f729Sjoerg
3507330f729Sjoerg    enum {
3517330f729Sjoerg      flagsPointy = 1
3527330f729Sjoerg      flagsHollow = 2
3537330f729Sjoerg      flagsFlat   = 4
3547330f729Sjoerg      flagsRound  = 8
3557330f729Sjoerg    };
3567330f729Sjoerg
3577330f729Sjoerg    LLVM_YAML_STRONG_TYPEDEF(uint32_t, MyFlags)
3587330f729Sjoerg
3597330f729SjoergTo support reading and writing of MyFlags, you specialize ScalarBitSetTraits<>
3607330f729Sjoergon MyFlags and provide the bit values and their names.
3617330f729Sjoerg
3627330f729Sjoerg.. code-block:: c++
3637330f729Sjoerg
3647330f729Sjoerg    using llvm::yaml::ScalarBitSetTraits;
3657330f729Sjoerg    using llvm::yaml::MappingTraits;
3667330f729Sjoerg    using llvm::yaml::IO;
3677330f729Sjoerg
3687330f729Sjoerg    template <>
3697330f729Sjoerg    struct ScalarBitSetTraits<MyFlags> {
3707330f729Sjoerg      static void bitset(IO &io, MyFlags &value) {
3717330f729Sjoerg        io.bitSetCase(value, "hollow",  flagHollow);
3727330f729Sjoerg        io.bitSetCase(value, "flat",    flagFlat);
3737330f729Sjoerg        io.bitSetCase(value, "round",   flagRound);
3747330f729Sjoerg        io.bitSetCase(value, "pointy",  flagPointy);
3757330f729Sjoerg      }
3767330f729Sjoerg    };
3777330f729Sjoerg
3787330f729Sjoerg    struct Info {
3797330f729Sjoerg      StringRef   name;
3807330f729Sjoerg      MyFlags     flags;
3817330f729Sjoerg    };
3827330f729Sjoerg
3837330f729Sjoerg    template <>
3847330f729Sjoerg    struct MappingTraits<Info> {
3857330f729Sjoerg      static void mapping(IO &io, Info& info) {
3867330f729Sjoerg        io.mapRequired("name",  info.name);
3877330f729Sjoerg        io.mapRequired("flags", info.flags);
3887330f729Sjoerg       }
3897330f729Sjoerg    };
3907330f729Sjoerg
3917330f729SjoergWith the above, YAML I/O (when writing) will test mask each value in the
3927330f729Sjoergbitset trait against the flags field, and each that matches will
3937330f729Sjoergcause the corresponding string to be added to the flow sequence.  The opposite
394*82d56013Sjoergis done when reading and any unknown string values will result in an error. With
3957330f729Sjoergthe above schema, a same valid YAML document is:
3967330f729Sjoerg
3977330f729Sjoerg.. code-block:: yaml
3987330f729Sjoerg
3997330f729Sjoerg    name:    Tom
4007330f729Sjoerg    flags:   [ pointy, flat ]
4017330f729Sjoerg
4027330f729SjoergSometimes a "flags" field might contains an enumeration part
4037330f729Sjoergdefined by a bit-mask.
4047330f729Sjoerg
4057330f729Sjoerg.. code-block:: c++
4067330f729Sjoerg
4077330f729Sjoerg    enum {
4087330f729Sjoerg      flagsFeatureA = 1,
4097330f729Sjoerg      flagsFeatureB = 2,
4107330f729Sjoerg      flagsFeatureC = 4,
4117330f729Sjoerg
4127330f729Sjoerg      flagsCPUMask = 24,
4137330f729Sjoerg
4147330f729Sjoerg      flagsCPU1 = 8,
4157330f729Sjoerg      flagsCPU2 = 16
4167330f729Sjoerg    };
4177330f729Sjoerg
4187330f729SjoergTo support reading and writing such fields, you need to use the maskedBitSet()
4197330f729Sjoergmethod and provide the bit values, their names and the enumeration mask.
4207330f729Sjoerg
4217330f729Sjoerg.. code-block:: c++
4227330f729Sjoerg
4237330f729Sjoerg    template <>
4247330f729Sjoerg    struct ScalarBitSetTraits<MyFlags> {
4257330f729Sjoerg      static void bitset(IO &io, MyFlags &value) {
4267330f729Sjoerg        io.bitSetCase(value, "featureA",  flagsFeatureA);
4277330f729Sjoerg        io.bitSetCase(value, "featureB",  flagsFeatureB);
4287330f729Sjoerg        io.bitSetCase(value, "featureC",  flagsFeatureC);
4297330f729Sjoerg        io.maskedBitSetCase(value, "CPU1",  flagsCPU1, flagsCPUMask);
4307330f729Sjoerg        io.maskedBitSetCase(value, "CPU2",  flagsCPU2, flagsCPUMask);
4317330f729Sjoerg      }
4327330f729Sjoerg    };
4337330f729Sjoerg
4347330f729SjoergYAML I/O (when writing) will apply the enumeration mask to the flags field,
4357330f729Sjoergand compare the result and values from the bitset. As in case of a regular
4367330f729Sjoergbitset, each that matches will cause the corresponding string to be added
4377330f729Sjoergto the flow sequence.
4387330f729Sjoerg
4397330f729SjoergCustom Scalar
4407330f729Sjoerg-------------
4417330f729SjoergSometimes for readability a scalar needs to be formatted in a custom way. For
442*82d56013Sjoerginstance your internal data structure may use an integer for time (seconds since
4437330f729Sjoergsome epoch), but in YAML it would be much nicer to express that integer in
4447330f729Sjoergsome time format (e.g. 4-May-2012 10:30pm).  YAML I/O has a way to support
4457330f729Sjoergcustom formatting and parsing of scalar types by specializing ScalarTraits<> on
4467330f729Sjoergyour data type.  When writing, YAML I/O will provide the native type and
4477330f729Sjoergyour specialization must create a temporary llvm::StringRef.  When reading,
4487330f729SjoergYAML I/O will provide an llvm::StringRef of scalar and your specialization
4497330f729Sjoergmust convert that to your native data type.  An outline of a custom scalar type
4507330f729Sjoerglooks like:
4517330f729Sjoerg
4527330f729Sjoerg.. code-block:: c++
4537330f729Sjoerg
4547330f729Sjoerg    using llvm::yaml::ScalarTraits;
4557330f729Sjoerg    using llvm::yaml::IO;
4567330f729Sjoerg
4577330f729Sjoerg    template <>
4587330f729Sjoerg    struct ScalarTraits<MyCustomType> {
4597330f729Sjoerg      static void output(const MyCustomType &value, void*,
4607330f729Sjoerg                         llvm::raw_ostream &out) {
4617330f729Sjoerg        out << value;  // do custom formatting here
4627330f729Sjoerg      }
4637330f729Sjoerg      static StringRef input(StringRef scalar, void*, MyCustomType &value) {
4647330f729Sjoerg        // do custom parsing here.  Return the empty string on success,
4657330f729Sjoerg        // or an error message on failure.
4667330f729Sjoerg        return StringRef();
4677330f729Sjoerg      }
4687330f729Sjoerg      // Determine if this scalar needs quotes.
4697330f729Sjoerg      static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
4707330f729Sjoerg    };
4717330f729Sjoerg
4727330f729SjoergBlock Scalars
4737330f729Sjoerg-------------
4747330f729Sjoerg
4757330f729SjoergYAML block scalars are string literals that are represented in YAML using the
4767330f729Sjoergliteral block notation, just like the example shown below:
4777330f729Sjoerg
4787330f729Sjoerg.. code-block:: yaml
4797330f729Sjoerg
4807330f729Sjoerg    text: |
4817330f729Sjoerg      First line
4827330f729Sjoerg      Second line
4837330f729Sjoerg
4847330f729SjoergThe YAML I/O library provides support for translating between YAML block scalars
4857330f729Sjoergand specific C++ types by allowing you to specialize BlockScalarTraits<> on
4867330f729Sjoergyour data type. The library doesn't provide any built-in support for block
4877330f729Sjoergscalar I/O for types like std::string and llvm::StringRef as they are already
4887330f729Sjoergsupported by YAML I/O and use the ordinary scalar notation by default.
4897330f729Sjoerg
4907330f729SjoergBlockScalarTraits specializations are very similar to the
4917330f729SjoergScalarTraits specialization - YAML I/O will provide the native type and your
4927330f729Sjoergspecialization must create a temporary llvm::StringRef when writing, and
4937330f729Sjoergit will also provide an llvm::StringRef that has the value of that block scalar
4947330f729Sjoergand your specialization must convert that to your native data type when reading.
4957330f729SjoergAn example of a custom type with an appropriate specialization of
4967330f729SjoergBlockScalarTraits is shown below:
4977330f729Sjoerg
4987330f729Sjoerg.. code-block:: c++
4997330f729Sjoerg
5007330f729Sjoerg    using llvm::yaml::BlockScalarTraits;
5017330f729Sjoerg    using llvm::yaml::IO;
5027330f729Sjoerg
5037330f729Sjoerg    struct MyStringType {
5047330f729Sjoerg      std::string Str;
5057330f729Sjoerg    };
5067330f729Sjoerg
5077330f729Sjoerg    template <>
5087330f729Sjoerg    struct BlockScalarTraits<MyStringType> {
5097330f729Sjoerg      static void output(const MyStringType &Value, void *Ctxt,
5107330f729Sjoerg                         llvm::raw_ostream &OS) {
5117330f729Sjoerg        OS << Value.Str;
5127330f729Sjoerg      }
5137330f729Sjoerg
5147330f729Sjoerg      static StringRef input(StringRef Scalar, void *Ctxt,
5157330f729Sjoerg                             MyStringType &Value) {
5167330f729Sjoerg        Value.Str = Scalar.str();
5177330f729Sjoerg        return StringRef();
5187330f729Sjoerg      }
5197330f729Sjoerg    };
5207330f729Sjoerg
5217330f729Sjoerg
5227330f729Sjoerg
5237330f729SjoergMappings
5247330f729Sjoerg========
5257330f729Sjoerg
5267330f729SjoergTo be translated to or from a YAML mapping for your type T you must specialize
5277330f729Sjoergllvm::yaml::MappingTraits on T and implement the "void mapping(IO &io, T&)"
5287330f729Sjoergmethod. If your native data structures use pointers to a class everywhere,
5297330f729Sjoergyou can specialize on the class pointer.  Examples:
5307330f729Sjoerg
5317330f729Sjoerg.. code-block:: c++
5327330f729Sjoerg
5337330f729Sjoerg    using llvm::yaml::MappingTraits;
5347330f729Sjoerg    using llvm::yaml::IO;
5357330f729Sjoerg
5367330f729Sjoerg    // Example of struct Foo which is used by value
5377330f729Sjoerg    template <>
5387330f729Sjoerg    struct MappingTraits<Foo> {
5397330f729Sjoerg      static void mapping(IO &io, Foo &foo) {
5407330f729Sjoerg        io.mapOptional("size",      foo.size);
5417330f729Sjoerg      ...
5427330f729Sjoerg      }
5437330f729Sjoerg    };
5447330f729Sjoerg
5457330f729Sjoerg    // Example of struct Bar which is natively always a pointer
5467330f729Sjoerg    template <>
5477330f729Sjoerg    struct MappingTraits<Bar*> {
5487330f729Sjoerg      static void mapping(IO &io, Bar *&bar) {
5497330f729Sjoerg        io.mapOptional("size",    bar->size);
5507330f729Sjoerg      ...
5517330f729Sjoerg      }
5527330f729Sjoerg    };
5537330f729Sjoerg
5547330f729Sjoerg
5557330f729SjoergNo Normalization
5567330f729Sjoerg----------------
5577330f729Sjoerg
5587330f729SjoergThe mapping() method is responsible, if needed, for normalizing and
5597330f729Sjoergdenormalizing. In a simple case where the native data structure requires no
5607330f729Sjoergnormalization, the mapping method just uses mapOptional() or mapRequired() to
5617330f729Sjoergbind the struct's fields to YAML key names.  For example:
5627330f729Sjoerg
5637330f729Sjoerg.. code-block:: c++
5647330f729Sjoerg
5657330f729Sjoerg    using llvm::yaml::MappingTraits;
5667330f729Sjoerg    using llvm::yaml::IO;
5677330f729Sjoerg
5687330f729Sjoerg    template <>
5697330f729Sjoerg    struct MappingTraits<Person> {
5707330f729Sjoerg      static void mapping(IO &io, Person &info) {
5717330f729Sjoerg        io.mapRequired("name",         info.name);
5727330f729Sjoerg        io.mapOptional("hat-size",     info.hatSize);
5737330f729Sjoerg      }
5747330f729Sjoerg    };
5757330f729Sjoerg
5767330f729Sjoerg
5777330f729SjoergNormalization
5787330f729Sjoerg----------------
5797330f729Sjoerg
5807330f729SjoergWhen [de]normalization is required, the mapping() method needs a way to access
5817330f729Sjoergnormalized values as fields. To help with this, there is
5827330f729Sjoerga template MappingNormalization<> which you can then use to automatically
5837330f729Sjoergdo the normalization and denormalization.  The template is used to create
5847330f729Sjoerga local variable in your mapping() method which contains the normalized keys.
5857330f729Sjoerg
5867330f729SjoergSuppose you have native data type
5877330f729SjoergPolar which specifies a position in polar coordinates (distance, angle):
5887330f729Sjoerg
5897330f729Sjoerg.. code-block:: c++
5907330f729Sjoerg
5917330f729Sjoerg    struct Polar {
5927330f729Sjoerg      float distance;
5937330f729Sjoerg      float angle;
5947330f729Sjoerg    };
5957330f729Sjoerg
5967330f729Sjoergbut you've decided the normalized YAML for should be in x,y coordinates. That
5977330f729Sjoergis, you want the yaml to look like:
5987330f729Sjoerg
5997330f729Sjoerg.. code-block:: yaml
6007330f729Sjoerg
6017330f729Sjoerg    x:   10.3
6027330f729Sjoerg    y:   -4.7
6037330f729Sjoerg
6047330f729SjoergYou can support this by defining a MappingTraits that normalizes the polar
6057330f729Sjoergcoordinates to x,y coordinates when writing YAML and denormalizes x,y
6067330f729Sjoergcoordinates into polar when reading YAML.
6077330f729Sjoerg
6087330f729Sjoerg.. code-block:: c++
6097330f729Sjoerg
6107330f729Sjoerg    using llvm::yaml::MappingTraits;
6117330f729Sjoerg    using llvm::yaml::IO;
6127330f729Sjoerg
6137330f729Sjoerg    template <>
6147330f729Sjoerg    struct MappingTraits<Polar> {
6157330f729Sjoerg
6167330f729Sjoerg      class NormalizedPolar {
6177330f729Sjoerg      public:
6187330f729Sjoerg        NormalizedPolar(IO &io)
6197330f729Sjoerg          : x(0.0), y(0.0) {
6207330f729Sjoerg        }
6217330f729Sjoerg        NormalizedPolar(IO &, Polar &polar)
6227330f729Sjoerg          : x(polar.distance * cos(polar.angle)),
6237330f729Sjoerg            y(polar.distance * sin(polar.angle)) {
6247330f729Sjoerg        }
6257330f729Sjoerg        Polar denormalize(IO &) {
6267330f729Sjoerg          return Polar(sqrt(x*x+y*y), arctan(x,y));
6277330f729Sjoerg        }
6287330f729Sjoerg
6297330f729Sjoerg        float        x;
6307330f729Sjoerg        float        y;
6317330f729Sjoerg      };
6327330f729Sjoerg
6337330f729Sjoerg      static void mapping(IO &io, Polar &polar) {
6347330f729Sjoerg        MappingNormalization<NormalizedPolar, Polar> keys(io, polar);
6357330f729Sjoerg
6367330f729Sjoerg        io.mapRequired("x",    keys->x);
6377330f729Sjoerg        io.mapRequired("y",    keys->y);
6387330f729Sjoerg      }
6397330f729Sjoerg    };
6407330f729Sjoerg
6417330f729SjoergWhen writing YAML, the local variable "keys" will be a stack allocated
6427330f729Sjoerginstance of NormalizedPolar, constructed from the supplied polar object which
6437330f729Sjoerginitializes it x and y fields.  The mapRequired() methods then write out the x
6447330f729Sjoergand y values as key/value pairs.
6457330f729Sjoerg
6467330f729SjoergWhen reading YAML, the local variable "keys" will be a stack allocated instance
6477330f729Sjoergof NormalizedPolar, constructed by the empty constructor.  The mapRequired
6487330f729Sjoergmethods will find the matching key in the YAML document and fill in the x and y
6497330f729Sjoergfields of the NormalizedPolar object keys. At the end of the mapping() method
6507330f729Sjoergwhen the local keys variable goes out of scope, the denormalize() method will
6517330f729Sjoergautomatically be called to convert the read values back to polar coordinates,
6527330f729Sjoergand then assigned back to the second parameter to mapping().
6537330f729Sjoerg
6547330f729SjoergIn some cases, the normalized class may be a subclass of the native type and
6557330f729Sjoergcould be returned by the denormalize() method, except that the temporary
6567330f729Sjoergnormalized instance is stack allocated.  In these cases, the utility template
6577330f729SjoergMappingNormalizationHeap<> can be used instead.  It just like
6587330f729SjoergMappingNormalization<> except that it heap allocates the normalized object
6597330f729Sjoergwhen reading YAML.  It never destroys the normalized object.  The denormalize()
6607330f729Sjoergmethod can this return "this".
6617330f729Sjoerg
6627330f729Sjoerg
6637330f729SjoergDefault values
6647330f729Sjoerg--------------
6657330f729SjoergWithin a mapping() method, calls to io.mapRequired() mean that that key is
6667330f729Sjoergrequired to exist when parsing YAML documents, otherwise YAML I/O will issue an
6677330f729Sjoergerror.
6687330f729Sjoerg
6697330f729SjoergOn the other hand, keys registered with io.mapOptional() are allowed to not
6707330f729Sjoergexist in the YAML document being read.  So what value is put in the field
6717330f729Sjoergfor those optional keys?
6727330f729SjoergThere are two steps to how those optional fields are filled in. First, the
6737330f729Sjoergsecond parameter to the mapping() method is a reference to a native class.  That
6747330f729Sjoergnative class must have a default constructor.  Whatever value the default
6757330f729Sjoergconstructor initially sets for an optional field will be that field's value.
6767330f729SjoergSecond, the mapOptional() method has an optional third parameter.  If provided
6777330f729Sjoergit is the value that mapOptional() should set that field to if the YAML document
6787330f729Sjoergdoes not have that key.
6797330f729Sjoerg
6807330f729SjoergThere is one important difference between those two ways (default constructor
6817330f729Sjoergand third parameter to mapOptional). When YAML I/O generates a YAML document,
6827330f729Sjoergif the mapOptional() third parameter is used, if the actual value being written
6837330f729Sjoergis the same as (using ==) the default value, then that key/value is not written.
6847330f729Sjoerg
6857330f729Sjoerg
6867330f729SjoergOrder of Keys
6877330f729Sjoerg--------------
6887330f729Sjoerg
6897330f729SjoergWhen writing out a YAML document, the keys are written in the order that the
6907330f729Sjoergcalls to mapRequired()/mapOptional() are made in the mapping() method. This
6917330f729Sjoerggives you a chance to write the fields in an order that a human reader of
6927330f729Sjoergthe YAML document would find natural.  This may be different that the order
6937330f729Sjoergof the fields in the native class.
6947330f729Sjoerg
6957330f729SjoergWhen reading in a YAML document, the keys in the document can be in any order,
6967330f729Sjoergbut they are processed in the order that the calls to mapRequired()/mapOptional()
6977330f729Sjoergare made in the mapping() method.  That enables some interesting
6987330f729Sjoergfunctionality.  For instance, if the first field bound is the cpu and the second
6997330f729Sjoergfield bound is flags, and the flags are cpu specific, you can programmatically
7007330f729Sjoergswitch how the flags are converted to and from YAML based on the cpu.
7017330f729SjoergThis works for both reading and writing. For example:
7027330f729Sjoerg
7037330f729Sjoerg.. code-block:: c++
7047330f729Sjoerg
7057330f729Sjoerg    using llvm::yaml::MappingTraits;
7067330f729Sjoerg    using llvm::yaml::IO;
7077330f729Sjoerg
7087330f729Sjoerg    struct Info {
7097330f729Sjoerg      CPUs        cpu;
7107330f729Sjoerg      uint32_t    flags;
7117330f729Sjoerg    };
7127330f729Sjoerg
7137330f729Sjoerg    template <>
7147330f729Sjoerg    struct MappingTraits<Info> {
7157330f729Sjoerg      static void mapping(IO &io, Info &info) {
7167330f729Sjoerg        io.mapRequired("cpu",       info.cpu);
7177330f729Sjoerg        // flags must come after cpu for this to work when reading yaml
7187330f729Sjoerg        if ( info.cpu == cpu_x86_64 )
7197330f729Sjoerg          io.mapRequired("flags",  *(My86_64Flags*)info.flags);
7207330f729Sjoerg        else
7217330f729Sjoerg          io.mapRequired("flags",  *(My86Flags*)info.flags);
7227330f729Sjoerg     }
7237330f729Sjoerg    };
7247330f729Sjoerg
7257330f729Sjoerg
7267330f729SjoergTags
7277330f729Sjoerg----
7287330f729Sjoerg
7297330f729SjoergThe YAML syntax supports tags as a way to specify the type of a node before
7307330f729Sjoergit is parsed. This allows dynamic types of nodes.  But the YAML I/O model uses
7317330f729Sjoergstatic typing, so there are limits to how you can use tags with the YAML I/O
7327330f729Sjoergmodel. Recently, we added support to YAML I/O for checking/setting the optional
733*82d56013Sjoergtag on a map. Using this functionality it is even possible to support different
7347330f729Sjoergmappings, as long as they are convertible.
7357330f729Sjoerg
7367330f729SjoergTo check a tag, inside your mapping() method you can use io.mapTag() to specify
7377330f729Sjoergwhat the tag should be.  This will also add that tag when writing yaml.
7387330f729Sjoerg
7397330f729SjoergValidation
7407330f729Sjoerg----------
7417330f729Sjoerg
7427330f729SjoergSometimes in a yaml map, each key/value pair is valid, but the combination is
7437330f729Sjoergnot.  This is similar to something having no syntax errors, but still having
7447330f729Sjoergsemantic errors.  To support semantic level checking, YAML I/O allows
7457330f729Sjoergan optional ``validate()`` method in a MappingTraits template specialization.
7467330f729Sjoerg
7477330f729SjoergWhen parsing yaml, the ``validate()`` method is call *after* all key/values in
7487330f729Sjoergthe map have been processed. Any error message returned by the ``validate()``
7497330f729Sjoergmethod during input will be printed just a like a syntax error would be printed.
7507330f729SjoergWhen writing yaml, the ``validate()`` method is called *before* the yaml
7517330f729Sjoergkey/values  are written.  Any error during output will trigger an ``assert()``
7527330f729Sjoergbecause it is a programming error to have invalid struct values.
7537330f729Sjoerg
7547330f729Sjoerg
7557330f729Sjoerg.. code-block:: c++
7567330f729Sjoerg
7577330f729Sjoerg    using llvm::yaml::MappingTraits;
7587330f729Sjoerg    using llvm::yaml::IO;
7597330f729Sjoerg
7607330f729Sjoerg    struct Stuff {
7617330f729Sjoerg      ...
7627330f729Sjoerg    };
7637330f729Sjoerg
7647330f729Sjoerg    template <>
7657330f729Sjoerg    struct MappingTraits<Stuff> {
7667330f729Sjoerg      static void mapping(IO &io, Stuff &stuff) {
7677330f729Sjoerg      ...
7687330f729Sjoerg      }
7697330f729Sjoerg      static StringRef validate(IO &io, Stuff &stuff) {
7707330f729Sjoerg        // Look at all fields in 'stuff' and if there
7717330f729Sjoerg        // are any bad values return a string describing
7727330f729Sjoerg        // the error.  Otherwise return an empty string.
7737330f729Sjoerg        return StringRef();
7747330f729Sjoerg      }
7757330f729Sjoerg    };
7767330f729Sjoerg
7777330f729SjoergFlow Mapping
7787330f729Sjoerg------------
7797330f729SjoergA YAML "flow mapping" is a mapping that uses the inline notation
7807330f729Sjoerg(e.g { x: 1, y: 0 } ) when written to YAML. To specify that a type should be
7817330f729Sjoergwritten in YAML using flow mapping, your MappingTraits specialization should
7827330f729Sjoergadd "static const bool flow = true;". For instance:
7837330f729Sjoerg
7847330f729Sjoerg.. code-block:: c++
7857330f729Sjoerg
7867330f729Sjoerg    using llvm::yaml::MappingTraits;
7877330f729Sjoerg    using llvm::yaml::IO;
7887330f729Sjoerg
7897330f729Sjoerg    struct Stuff {
7907330f729Sjoerg      ...
7917330f729Sjoerg    };
7927330f729Sjoerg
7937330f729Sjoerg    template <>
7947330f729Sjoerg    struct MappingTraits<Stuff> {
7957330f729Sjoerg      static void mapping(IO &io, Stuff &stuff) {
7967330f729Sjoerg        ...
7977330f729Sjoerg      }
7987330f729Sjoerg
7997330f729Sjoerg      static const bool flow = true;
8007330f729Sjoerg    }
8017330f729Sjoerg
8027330f729SjoergFlow mappings are subject to line wrapping according to the Output object
8037330f729Sjoergconfiguration.
8047330f729Sjoerg
8057330f729SjoergSequence
8067330f729Sjoerg========
8077330f729Sjoerg
8087330f729SjoergTo be translated to or from a YAML sequence for your type T you must specialize
8097330f729Sjoergllvm::yaml::SequenceTraits on T and implement two methods:
8107330f729Sjoerg``size_t size(IO &io, T&)`` and
8117330f729Sjoerg``T::value_type& element(IO &io, T&, size_t indx)``.  For example:
8127330f729Sjoerg
8137330f729Sjoerg.. code-block:: c++
8147330f729Sjoerg
8157330f729Sjoerg  template <>
8167330f729Sjoerg  struct SequenceTraits<MySeq> {
8177330f729Sjoerg    static size_t size(IO &io, MySeq &list) { ... }
8187330f729Sjoerg    static MySeqEl &element(IO &io, MySeq &list, size_t index) { ... }
8197330f729Sjoerg  };
8207330f729Sjoerg
8217330f729SjoergThe size() method returns how many elements are currently in your sequence.
8227330f729SjoergThe element() method returns a reference to the i'th element in the sequence.
8237330f729SjoergWhen parsing YAML, the element() method may be called with an index one bigger
8247330f729Sjoergthan the current size.  Your element() method should allocate space for one
8257330f729Sjoergmore element (using default constructor if element is a C++ object) and returns
8267330f729Sjoerga reference to that new allocated space.
8277330f729Sjoerg
8287330f729Sjoerg
8297330f729SjoergFlow Sequence
8307330f729Sjoerg-------------
8317330f729SjoergA YAML "flow sequence" is a sequence that when written to YAML it uses the
8327330f729Sjoerginline notation (e.g [ foo, bar ] ).  To specify that a sequence type should
8337330f729Sjoergbe written in YAML as a flow sequence, your SequenceTraits specialization should
8347330f729Sjoergadd "static const bool flow = true;".  For instance:
8357330f729Sjoerg
8367330f729Sjoerg.. code-block:: c++
8377330f729Sjoerg
8387330f729Sjoerg  template <>
8397330f729Sjoerg  struct SequenceTraits<MyList> {
8407330f729Sjoerg    static size_t size(IO &io, MyList &list) { ... }
8417330f729Sjoerg    static MyListEl &element(IO &io, MyList &list, size_t index) { ... }
8427330f729Sjoerg
8437330f729Sjoerg    // The existence of this member causes YAML I/O to use a flow sequence
8447330f729Sjoerg    static const bool flow = true;
8457330f729Sjoerg  };
8467330f729Sjoerg
8477330f729SjoergWith the above, if you used MyList as the data type in your native data
8487330f729Sjoergstructures, then when converted to YAML, a flow sequence of integers
8497330f729Sjoergwill be used (e.g. [ 10, -3, 4 ]).
8507330f729Sjoerg
8517330f729SjoergFlow sequences are subject to line wrapping according to the Output object
8527330f729Sjoergconfiguration.
8537330f729Sjoerg
8547330f729SjoergUtility Macros
8557330f729Sjoerg--------------
8567330f729SjoergSince a common source of sequences is std::vector<>, YAML I/O provides macros:
8577330f729SjoergLLVM_YAML_IS_SEQUENCE_VECTOR() and LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR() which
8587330f729Sjoergcan be used to easily specify SequenceTraits<> on a std::vector type.  YAML
8597330f729SjoergI/O does not partial specialize SequenceTraits on std::vector<> because that
8607330f729Sjoergwould force all vectors to be sequences.  An example use of the macros:
8617330f729Sjoerg
8627330f729Sjoerg.. code-block:: c++
8637330f729Sjoerg
8647330f729Sjoerg  std::vector<MyType1>;
8657330f729Sjoerg  std::vector<MyType2>;
8667330f729Sjoerg  LLVM_YAML_IS_SEQUENCE_VECTOR(MyType1)
8677330f729Sjoerg  LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(MyType2)
8687330f729Sjoerg
8697330f729Sjoerg
8707330f729Sjoerg
8717330f729SjoergDocument List
8727330f729Sjoerg=============
8737330f729Sjoerg
8747330f729SjoergYAML allows you to define multiple "documents" in a single YAML file.  Each
8757330f729Sjoergnew document starts with a left aligned "---" token.  The end of all documents
8767330f729Sjoergis denoted with a left aligned "..." token.  Many users of YAML will never
8777330f729Sjoerghave need for multiple documents.  The top level node in their YAML schema
8787330f729Sjoergwill be a mapping or sequence. For those cases, the following is not needed.
8797330f729SjoergBut for cases where you do want multiple documents, you can specify a
8807330f729Sjoergtrait for you document list type.  The trait has the same methods as
8817330f729SjoergSequenceTraits but is named DocumentListTraits.  For example:
8827330f729Sjoerg
8837330f729Sjoerg.. code-block:: c++
8847330f729Sjoerg
8857330f729Sjoerg  template <>
8867330f729Sjoerg  struct DocumentListTraits<MyDocList> {
8877330f729Sjoerg    static size_t size(IO &io, MyDocList &list) { ... }
8887330f729Sjoerg    static MyDocType element(IO &io, MyDocList &list, size_t index) { ... }
8897330f729Sjoerg  };
8907330f729Sjoerg
8917330f729Sjoerg
8927330f729SjoergUser Context Data
8937330f729Sjoerg=================
8947330f729SjoergWhen an llvm::yaml::Input or llvm::yaml::Output object is created their
8957330f729Sjoergconstructors take an optional "context" parameter.  This is a pointer to
8967330f729Sjoergwhatever state information you might need.
8977330f729Sjoerg
8987330f729SjoergFor instance, in a previous example we showed how the conversion type for a
8997330f729Sjoergflags field could be determined at runtime based on the value of another field
9007330f729Sjoergin the mapping. But what if an inner mapping needs to know some field value
9017330f729Sjoergof an outer mapping?  That is where the "context" parameter comes in. You
9027330f729Sjoergcan set values in the context in the outer map's mapping() method and
9037330f729Sjoergretrieve those values in the inner map's mapping() method.
9047330f729Sjoerg
9057330f729SjoergThe context value is just a void*.  All your traits which use the context
9067330f729Sjoergand operate on your native data types, need to agree what the context value
9077330f729Sjoergactually is.  It could be a pointer to an object or struct which your various
9087330f729Sjoergtraits use to shared context sensitive information.
9097330f729Sjoerg
9107330f729Sjoerg
9117330f729SjoergOutput
9127330f729Sjoerg======
9137330f729Sjoerg
9147330f729SjoergThe llvm::yaml::Output class is used to generate a YAML document from your
9157330f729Sjoergin-memory data structures, using traits defined on your data types.
9167330f729SjoergTo instantiate an Output object you need an llvm::raw_ostream, an optional
9177330f729Sjoergcontext pointer and an optional wrapping column:
9187330f729Sjoerg
9197330f729Sjoerg.. code-block:: c++
9207330f729Sjoerg
9217330f729Sjoerg      class Output : public IO {
9227330f729Sjoerg      public:
9237330f729Sjoerg        Output(llvm::raw_ostream &, void *context = NULL, int WrapColumn = 70);
9247330f729Sjoerg
9257330f729SjoergOnce you have an Output object, you can use the C++ stream operator on it
9267330f729Sjoergto write your native data as YAML. One thing to recall is that a YAML file
9277330f729Sjoergcan contain multiple "documents".  If the top level data structure you are
9287330f729Sjoergstreaming as YAML is a mapping, scalar, or sequence, then Output assumes you
9297330f729Sjoergare generating one document and wraps the mapping output
9307330f729Sjoergwith  "``---``" and trailing "``...``".
9317330f729Sjoerg
9327330f729SjoergThe WrapColumn parameter will cause the flow mappings and sequences to
9337330f729Sjoergline-wrap when they go over the supplied column. Pass 0 to completely
9347330f729Sjoergsuppress the wrapping.
9357330f729Sjoerg
9367330f729Sjoerg.. code-block:: c++
9377330f729Sjoerg
9387330f729Sjoerg    using llvm::yaml::Output;
9397330f729Sjoerg
9407330f729Sjoerg    void dumpMyMapDoc(const MyMapType &info) {
9417330f729Sjoerg      Output yout(llvm::outs());
9427330f729Sjoerg      yout << info;
9437330f729Sjoerg    }
9447330f729Sjoerg
9457330f729SjoergThe above could produce output like:
9467330f729Sjoerg
9477330f729Sjoerg.. code-block:: yaml
9487330f729Sjoerg
9497330f729Sjoerg     ---
9507330f729Sjoerg     name:      Tom
9517330f729Sjoerg     hat-size:  7
9527330f729Sjoerg     ...
9537330f729Sjoerg
9547330f729SjoergOn the other hand, if the top level data structure you are streaming as YAML
9557330f729Sjoerghas a DocumentListTraits specialization, then Output walks through each element
9567330f729Sjoergof your DocumentList and generates a "---" before the start of each element
9577330f729Sjoergand ends with a "...".
9587330f729Sjoerg
9597330f729Sjoerg.. code-block:: c++
9607330f729Sjoerg
9617330f729Sjoerg    using llvm::yaml::Output;
9627330f729Sjoerg
9637330f729Sjoerg    void dumpMyMapDoc(const MyDocListType &docList) {
9647330f729Sjoerg      Output yout(llvm::outs());
9657330f729Sjoerg      yout << docList;
9667330f729Sjoerg    }
9677330f729Sjoerg
9687330f729SjoergThe above could produce output like:
9697330f729Sjoerg
9707330f729Sjoerg.. code-block:: yaml
9717330f729Sjoerg
9727330f729Sjoerg     ---
9737330f729Sjoerg     name:      Tom
9747330f729Sjoerg     hat-size:  7
9757330f729Sjoerg     ---
9767330f729Sjoerg     name:      Tom
9777330f729Sjoerg     shoe-size:  11
9787330f729Sjoerg     ...
9797330f729Sjoerg
9807330f729SjoergInput
9817330f729Sjoerg=====
9827330f729Sjoerg
9837330f729SjoergThe llvm::yaml::Input class is used to parse YAML document(s) into your native
9847330f729Sjoergdata structures. To instantiate an Input
9857330f729Sjoergobject you need a StringRef to the entire YAML file, and optionally a context
9867330f729Sjoergpointer:
9877330f729Sjoerg
9887330f729Sjoerg.. code-block:: c++
9897330f729Sjoerg
9907330f729Sjoerg      class Input : public IO {
9917330f729Sjoerg      public:
9927330f729Sjoerg        Input(StringRef inputContent, void *context=NULL);
9937330f729Sjoerg
9947330f729SjoergOnce you have an Input object, you can use the C++ stream operator to read
9957330f729Sjoergthe document(s).  If you expect there might be multiple YAML documents in
9967330f729Sjoergone file, you'll need to specialize DocumentListTraits on a list of your
9977330f729Sjoergdocument type and stream in that document list type.  Otherwise you can
9987330f729Sjoergjust stream in the document type.  Also, you can check if there was
9997330f729Sjoergany syntax errors in the YAML be calling the error() method on the Input
10007330f729Sjoergobject.  For example:
10017330f729Sjoerg
10027330f729Sjoerg.. code-block:: c++
10037330f729Sjoerg
10047330f729Sjoerg     // Reading a single document
10057330f729Sjoerg     using llvm::yaml::Input;
10067330f729Sjoerg
10077330f729Sjoerg     Input yin(mb.getBuffer());
10087330f729Sjoerg
10097330f729Sjoerg     // Parse the YAML file
10107330f729Sjoerg     MyDocType theDoc;
10117330f729Sjoerg     yin >> theDoc;
10127330f729Sjoerg
10137330f729Sjoerg     // Check for error
10147330f729Sjoerg     if ( yin.error() )
10157330f729Sjoerg       return;
10167330f729Sjoerg
10177330f729Sjoerg
10187330f729Sjoerg.. code-block:: c++
10197330f729Sjoerg
10207330f729Sjoerg     // Reading multiple documents in one file
10217330f729Sjoerg     using llvm::yaml::Input;
10227330f729Sjoerg
10237330f729Sjoerg     LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(MyDocType)
10247330f729Sjoerg
10257330f729Sjoerg     Input yin(mb.getBuffer());
10267330f729Sjoerg
10277330f729Sjoerg     // Parse the YAML file
10287330f729Sjoerg     std::vector<MyDocType> theDocList;
10297330f729Sjoerg     yin >> theDocList;
10307330f729Sjoerg
10317330f729Sjoerg     // Check for error
10327330f729Sjoerg     if ( yin.error() )
10337330f729Sjoerg       return;
10347330f729Sjoerg
10357330f729Sjoerg
1036