<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div>Sean,</div><div><br></div><div>I've working on reimplementing YAML I/O to use a traits based approach.  I'm using lld's internal object as a test bed.  The File/Atom/Reference objects in lld have no public ivars.  Everything is accessed through virtual methods.  So, if I can do yaml I/O on those classes just by defining trait specializations, then the mechanism should be very adaptable. </div><div><br></div><div>I have something working now, but it is all using C++11.  I still need to discover what issues will arise when used by C++03.  </div><div><br></div><div>Here is a flavor of what I have working.  I want to make sure this is the right direction:</div><div><br></div><div><div>If you have an enum like:</div><div><br></div><div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; "><span style="color: #ba00a1">   enum</span> Color { cRed, cBlue, cGreen };</div></div><div><br></div></div><div><div>You can write a trait like this:</div></div><div><br></div><div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; color: rgb(186, 0, 161); ">  template<span style="color: #000000"> <></span></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; "><span style="color: #ba00a1">  struct</span> llvm::yaml::ScalarTrait<Color> {</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">    <span style="color: #ba00a1">static</span> <span style="color: #ba00a1">void</span> doScalar(IO &io, Color &value) {</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      io.beginEnumScalar();</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      io.enumScalarMatch(value, <span style="color: #cd2324">"red"</span>,   cRed);</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      io.enumScalarMatch(value, <span style="color: #cd2324">"blue"</span>,  cBlue);</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; "><span class="Apple-style-span">      io.enumScalarMatch(value, <span style="color: #cd2324">"green"</span>, </span>cGreen<span class="Apple-style-span">);</span></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      io.endEnumScalar();</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">    }</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">  };</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; min-height: 13px; "><br></div></div><div>Which describes how to convert the in-memory enum value to a yaml scalar and back.  I'm also working on a way that you can do arbitrary conversion of scalars.  </div><div><br></div><div><br></div><div><div>If you have a simple POD struct like this:</div><div><br></div><div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; "><span style="color: rgb(186, 0, 161); ">struct</span> MyInfo {</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">  <span style="color: rgb(186, 0, 161); ">int</span>    hat_size;</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">  <span style="color: rgb(186, 0, 161); ">int</span>    age;</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">  Color  hat_color;</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">};</div></div><div><br></div><div>You can write a trait like this:</div><div><br></div><div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; color: rgb(186, 0, 161); ">template<span style="color: rgb(0, 0, 0); "> <></span></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; "><span style="color: rgb(186, 0, 161); ">struct</span> llvm::yaml::MapTraits<MyInfo> {</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">  <span style="color: rgb(186, 0, 161); ">static</span> <span style="color: rgb(186, 0, 161); ">void</span> mapping(IO &io, MyInfo& info) {</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">    io.reqKey(<span style="color: rgb(205, 35, 36); ">"hat-size"</span>,    info.hat_size);</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">    io.optKey(<span style="color: rgb(205, 35, 36); ">"age"</span>,         info.age,         <span style="color: rgb(62, 0, 214); ">21</span>);</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; "><span class="Apple-style-span">    io.optKey(<span style="color: rgb(205, 35, 36); ">"hat-color"</span>,   </span>hat_color<span class="Apple-style-span">,        </span>cBlue<span class="Apple-style-span">);</span></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">  }</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">};</div></div><div><br></div><div>Which is used to both read and write yaml.   The "age" and "hat-color" keys are optional in yaml.  If not specified (in yaml), they default to 21 and cBlue. The "hat-size" key is required, and you will get an error it is not present in the yaml.</div></div><div><br></div><div>There is no trait for yaml sequences.  Instead, if your data type is a class with begin, end, and push_back methods, it is assumed to be a sequence.</div><div><br></div><div><br></div><div>Now, the interesting case is the handling of non-POD data types.  The reqKey() and optKey() methods need a lvalue to they can be read (when creating yaml) and write (when parsing yaml).  It may also be the case that your existing data structures is not a container of structs, but a container of pointers to structs.  But in both those cases, you want to be able to have the same yaml representation.  Lastly, in the parsing yaml case, you need to be able to instantiate an internal object, whereas the writing yaml case needs to examine an existing object.</div><div><br></div><div>Here is an example of the lld Reference type and the trait for converting it to and from yaml:</div><div><br></div><div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; "><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; color: rgb(186, 0, 161); "><span style="color: #000000">  </span>template<span style="color: #000000"> <></span></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">  <span style="color: #ba00a1">struct</span> MapTraits<<span style="color: #ba00a1">const</span> lld::Reference*> {</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; min-height: 13px; "><br></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">    <span style="color: #ba00a1">class</span> MyReference : <span style="color: #ba00a1">public</span> lld::Reference {</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; color: rgb(186, 0, 161); "><span style="color: #000000">    </span>public<span style="color: #000000">:</span></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      MyReference()</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">        : _target(nullptr), _targetName(), _offset(<span style="color: #3e00d6">0</span>), _addend(<span style="color: #3e00d6">0</span>) , _kind(<span style="color: #3e00d6">0</span>) {</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      }</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      MyReference(<span style="color: #ba00a1">const</span> lld::Reference* ref)</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">        : _target(nullptr), </div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">        _targetName(ref->target() ? ref->target()->name() : <span style="color: #cd2324">""</span>), </div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">        _offset(ref->offsetInAtom()), </div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">        _addend(ref->addend()),</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">        _kind(ref->kind()) {</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      }</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; min-height: 13px; "><br></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      <span style="color: #ba00a1">virtual</span> uint64_t         offsetInAtom() <span style="color: #ba00a1">const</span> { <span style="color: #ba00a1">return</span> _offset; }</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      <span style="color: #ba00a1">virtual</span> Kind             kind() <span style="color: #ba00a1">const</span>         { <span style="color: #ba00a1">return</span> _kind; }</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      <span style="color: #ba00a1">virtual</span> <span style="color: #ba00a1">const</span> lld::Atom *target() <span style="color: #ba00a1">const</span>       { <span style="color: #ba00a1">return</span> _target; }</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      <span style="color: #ba00a1">virtual</span> Addend           addend() <span style="color: #ba00a1">const</span>       { <span style="color: #ba00a1">return</span> _addend; }</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      <span style="color: #ba00a1">virtual</span> <span style="color: #ba00a1">void</span>             setKind(Kind k)      { _kind = k; }</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      <span style="color: #ba00a1">virtual</span> <span style="color: #ba00a1">void</span>             setAddend(Addend a)  { _addend = a; }</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      <span style="color: #ba00a1">virtual</span> <span style="color: #ba00a1">void</span>             setTarget(<span style="color: #ba00a1">const</span> lld::Atom *a) { _target = a; }</div><p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; min-height: 13.0px">      <br class="webkit-block-placeholder"></p><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      <span style="color: #ba00a1">const</span> lld::Atom *_target;</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      StringRef        _targetName;</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      uint32_t         _offset;</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      Addend           _addend;</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      Kind             _kind;</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">    };</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; min-height: 13px; "><br></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; min-height: 13px; "><br></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">    <span style="color: #ba00a1">static</span> <span style="color: #ba00a1">void</span> mapping(IO &io, <span style="color: #ba00a1">const</span> lld::Reference*& ref) {</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      MappingHelper<MyReference, <span style="color: #ba00a1">const</span> lld::Reference*> keys(io, ref);</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; min-height: 13px; "><br></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      io.reqKey(<span style="color: #cd2324">"kind"</span>,           keys->_kind);</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      io.optKey(<span style="color: #cd2324">"offset"</span>,         keys->_offset);</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      io.optKey(<span style="color: #cd2324">"target"</span>,         keys->_targetName);</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">      io.optKey(<span style="color: #cd2324">"addend"</span>,         keys->_addend);</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">    }</div><p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; min-height: 13.0px">    <br class="webkit-block-placeholder"></p><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; ">  };</div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Menlo; min-height: 13px; "><br></div></div></div><div>Some salient points:</div><div>* The trait is on "const lld::Reference*" because only pointers to References are passed around inside lld.</div><div>* The lld class Reference in an abstract base class, so a concrete instance must be defined (MyReference).</div><div>* There are two constructors for MyReference.  The default  constructor is used when parsing yaml to create the initial object which is then overridden as key/values are found in yaml.  The other constructor is used when writing yaml to create a temporary (stack) instance which contains the fields needed for mapping() to access.</div><div>* MappingHelper<> is a utility which detects if you are reading or writing and constructs the appropriate object.  It is only needed for non-POD structs.</div><div><br></div><div>-Nick</div><div><br></div><div><div>On Aug 8, 2012, at 6:34 PM, Sean Silva wrote:</div><blockquote type="cite"><div><blockquote type="cite">Your suggestion is to remove the intermediate data structures and instead define the schema via external trait templates.   I can see how this would seem easier (not having to write glue code to copy to and from the intermediate data types).  But that copying also does normalization.  For instance, your native object may have two ivars that together make one yaml key-value, or one ivar is best represented a as couple of yaml key-values.  Or your sequence may have a preferred sort order in yaml, but that is not the actual list order in memory.<br></blockquote><br>I don't get what you're saying here. A traits class can easily handle<br>all those conversions easily.<br><br>It would look something like:<br><br>template<><br>class YamlMapTraits<Person> {<br>  void yamlMapping(IO &io, Person *P) {<br>    requiredKey(io, &P->name, "name");<br>    optionalKey(io, &P->hatSize, "hat-size");<br>  }<br>};<br><br>Here I was just trying to mimic the one of the examples from your<br>documentation so the feel should be similar. However, the door is open<br>to specifying the correspondence however you really want in the traits<br>class.<br><br><blockquote type="cite">I think the hard part of a traits approach is figuring out how clients will write the normalization code.  And how to make the difficulty of that code scale to how denormalized the native objects are.<br></blockquote><br>One possibility I can think of off the top of my head is to have the<br>traits class declare a private intermediate struct which it<br>deserializes to (similar to the intermediate that the current API<br>_forces_ you to have), and then just construct the object from the<br>intermediate. It's so much more flexible to do this with a traits<br>class.<br><br>--Sean Silva<br><br>On Wed, Aug 8, 2012 at 5:34 PM, Nick Kledzik <<a href="mailto:kledzik@apple.com">kledzik@apple.com</a>> wrote:<br><blockquote type="cite"><br></blockquote><blockquote type="cite">On Aug 8, 2012, at 12:46 PM, Sean Silva wrote:<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">But EnumValue is not quite right because it can be used with #defines too.<br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">Do we really want to encourage people to use #defines? Is there any<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">set of constants in the LLVM tree which are defined with #defines and<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">not in an enum?<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">I'm not sure what you mean by traits-based in this context.<br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">A traits-based design means that you have a class template which<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">provides a collection of type-specific information which is provided<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">by specializing the class template for a particular type. For example,<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">see include/llvm/ADT/GraphTraits.h, which uses GraphTraits<T> to<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">specify how to adapt T to a common interface that graph algorithms can<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">use. This is noninvasive (maybe needing a friend declaration at most).<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">Your current approach using inheritance and virtual functions is<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">invasive, forces the serializable class to inherit (causing multiple<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">inheritance in the case that the serializable class already has a<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">base), and forces the serializable class to suddenly have virtual<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">functions.<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">Overall, I think a traits-based design would be simpler, more loosely<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">coupled, and seems to fit the use case more naturally.<br></blockquote></blockquote><blockquote type="cite">I as wrote in the documentation this was not intended to allow you to go directly from existing data structures to yaml and back.  Instead the schema "language" is written in terms of new data structure declarations (subclass of YamlMap and specialization of Sequence<>).<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">Your suggestion is to remove the intermediate data structures and instead define the schema via external trait templates.   I can see how this would seem easier (not having to write glue code to copy to and from the intermediate data types).  But that copying also does normalization.  For instance, your native object may have two ivars that together make one yaml key-value, or one ivar is best represented a as couple of yaml key-values.  Or your sequence may have a preferred sort order in yaml, but that is not the actual list order in memory.<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">I think the hard part of a traits approach is figuring out how clients will write the normalization code.  And how to make the difficulty of that code scale to how denormalized the native objects are.<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">I'll play around with this idea and see what works and what does not.<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">-Nick<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">On Tue, Aug 7, 2012 at 4:57 PM, Nick Kledzik <<a href="mailto:kledzik@apple.com">kledzik@apple.com</a>> wrote:<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">On Aug 7, 2012, at 2:07 PM, Sean Silva wrote:<br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">Thanks for writing awesome docs!<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">+Sometime sequences are known to be short and the one entry per line is too<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">+verbose, so YAML offers an alternate syntax for sequences called a "Flow<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">+Sequence" in which you put comma separated sequence elements into square<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">+brackets.  The above example could then be simplified to :<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">It's probably worth mentioning here that the "Flow" syntax is<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">(exactly?) JSON. Also, noting that JSON is a proper subset of YAML is<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">in general is probably worth mentioning.<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">+   .. code-block:: none<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">pygments (and hence Sphinx) supports `yaml` highlighting<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><<a href="http://pygments.org/docs/lexers/">http://pygments.org/docs/lexers/</a>><br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">+the following document:<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">+<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">+   .. code-block:: none<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">The precedent for code listings is generally that the `..<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">code-block::` is at the same level of indentation as the paragraph<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">introducing it.<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">+You can combine mappings and squences by indenting.  For example a sequence<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">+of mappings in which one of the mapping values is itself a sequence:<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">s/squences/sequences/<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">+of a new document is denoted with "---".  So in order for Input to handle<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">+multiple documents, it operators on an llvm::yaml::Document<>.<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">s/operators/operates/<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">+can set values in the context in the outer map's yamlMapping() method and<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">+retrive those values in the inner map's yamlMapping() method.<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">s/retrive/retrieve/<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">+of a new document is denoted with "---".  So in order for Input to handle<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">For clarity, I would put the --- in monospace (e.g. "``---``"), here<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">and in other places.<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">Thanks for the Sphinx tips.  I've incorporated them and ran a spell checker too ;-)<br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">+UniqueValue<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">+-----------<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">I think that EnumValue be more self-documenting than UniqueValue.<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">I'm happy to give UniqueValue a better name.  But EnumValue is not quite right because it can be used with #defines too.  The real constraint is that there be a one-to-one mapping of strings to values.    I want it to contrast with BitValue which maps a set (sequence) of strings to a set of values OR'ed together.<br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">At a design level, what are the pros/cons of this approach compared<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">with a traits-based approach? What made you choose this design versus<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">a traits-based approach?<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">I'm not sure what you mean by traits-based in this context.    The back story is that for lld I've been writing code to read and write yaml documents.  Michael's YAMLParser.h certainly makes reading more robust, but there is still tons of (semantic level) error checking you to hand code.  It seemed like most of my code was checking for errors.  Also it was a pain to keep the yaml reading code is sync with yaml writing code.<br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">What we really need was a way to describe the schema of the yaml documents and have some tool generate the code to read and write.  There is a tool called Kwalify which defines a way to express a yaml schema and can check it.  But it has a number of limitations.<br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">Last month a wrote up a proposal for defining a yaml schema language and a tool that would use that schema to generate C++ code to read/validate and write yaml conforming to the schema.  The best feedback I got  (from Daniel Dunbar) was that rather than create another language (yaml schema language) and tools, to try to see if you could express the schema in C++ directly, using meta-programming or whatever.   I looked at Boost serialization for inspiration and came up with this Yaml I/O library.<br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">-Nick<br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">On Mon, Aug 6, 2012 at 12:17 PM, Nick Kledzik <<a href="mailto:kledzik@apple.com">kledzik@apple.com</a>> wrote:<br></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">Attached is a patch for review which implements the Yaml I/O library I proposed on llvm-dev July 25th.<br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">The patch includes the implementation, test cases, and documentation.<br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">I've included a PDF of the documentation, so you don't have to install the patch and run sphinx to read it.<br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">There are probably more aspects of yaml we can support in YAML I/O, but the current patch is enough to support my needs for encoding mach-o as yaml for lld test cases.<br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">I was initially planning on just adding this code to lld, but I've had two requests to push it down into llvm.<br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">Again, here are examples of the mach-o schema and an example mach-o document:<br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">-Nick<br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">_______________________________________________<br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">llvm-commits mailing list<br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote></blockquote><blockquote type="cite"><br></blockquote></div></blockquote></div><br></body></html>