vk.xml

Nicholas Wilson via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sun Feb 21 23:00:42 PST 2016


On Sunday, 21 February 2016 at 15:18:44 UTC, ZombineDev wrote:
> On Sunday, 21 February 2016 at 12:52:33 UTC, Nicholas Wilson 
> wrote:
>> So I was going through the vulcan spec to try to create a 
>> better D bindings for it. (pointer /len pairs to arrays 
>> adhering to D naming conventions and prettying up the *Create 
>> functions functions like vkResult *Create( arg ,&arg, retptr) 
>> to a fancy throw on misuse struct with constructors and that 
>> kind of stuff.)
>>
>>  the structure of the registry is as follows.
>>
>>
>> struct KHR_registry
>> {
>> <snip>
>> }
>>
>
> I'm glad to see more people looking to create a D binding from 
> vk.xml!
> I was also working on this 
> (http://forum.dlang.org/post/ygylvtuwwiwyqtcnlejh@forum.dlang.org), unfortunately I won't be able to continue my work until early March, so I hope you'll do a good job in the mean time ;)
>
> Unfortunately the spec is written in a very C specific way so 
> we need to have a bunch of special cases for parsing the C code 
> that's interleaved with the XML tags.
>
> I haven't used std.xml yet, but I hope I may be able to help 
> you.
>
>> where "string content" is the string between the tags (does 
>> this have a name?) and thing with @Tag are always in the tag 
>> (although it is also inconsistent). I tried looking at the 
>> docs for std.xml but they were not very helpful.
>
> May be you can use
> http://dlang.org/phobos/std_xml#.Element.text in combination 
> with
> http://dlang.org/phobos/std_xml#.Element.elements
>
>> To further complicate things not all of the fields are present 
>> in all cases also I need to keep track of the number of '*' 
>> (see fields named indirections) after a tag has closed  for 
>> pointer type declarations in function signatures and structs.
>
> You mean things like:
> <param><type>void</type>** <name>ppData</name></param>
> (from the vkMapMemory command) ?
>
> Yeah this is extremely ugly.
> One way to do it is to go to the "param" XML element
> and check if the size of it's elements matches it's text size. 
> In the case above everything between <param>  and </param> is 
> 39 characters and the two tags are
> 17 and 19 character respectively (total 36) which leaves 3 
> chars for the indirections. If we make a pass to remove all 
> whitespace between tags (between ">" and "<") we should get 
> exactly 2 characters which is the number of indirection we're 
> looking for.
>
> Another way is to just strip the tags and leave only their 
> internal text. In the above example the result should be:
> <param>void** ppData</param>
> which is valid D code and we can leave it that way for now.
>
>> Also is there a way to do sane cross referencing without 
>> having internal pointers everywhere.
>
> I am no XML expert (so there may be an easier way), but I think 
> it would be easier if we use associative arrays, instead of 
> plain arrays. That way we can check for example:
>
> if ("VkBuffer" in types && "VkDevice" in types)
>     types["VkBuffer"].parent = types["VkDevice"];
>
>> I'm sure there should be a very elegant way to do this by 
>> recursing down through the sub-structs
>
> The simplest solution, IMO, is to insert all the types, 
> commands, enums, etc. in associative arrays first and then do 
> cross-referencing.
>
> E.g.
>
> Type[string] types;
> struct Type
> {
>    // ... other members
>
>    // Set to string first, and later change
>    // to the proper Type, after the whole `types` table has 
> been read.
>    Algebraic(string, Type*) parent;
>
>    // ... more members
> }
>
> Otherwise the only sane way to do forward reference resolution 
> is to use D Fibers. I have used fibers in some of my projects, 
> but the extra complications are not worth it for this task as 
> the xml is only 5100 lines and the performance benefits 
> probably would not be very large.
>
>> Many thanks
>> Nic
>
> BTW if you run into some other issues with std.xml, you can 
> also check
> http://arsdnet.net/web.d/dom.html and
> https://github.com/burner/std.xml2
>
> Also don't forget to use unittests extensively!

Thanks for the tips. I used AA and just got it to compile! :) :| 
:( but fails to link.
Undefined symbols for architecture x86_64:
   "_D28TypeInfo_xC4arsd3dom7Element6__initZ", referenced from:
       _D29TypeInfo_AxC4arsd3dom7Element6__initZ in app.o
   "_D4arsd3dom12__ModuleInfoZ", referenced from:
       _D3app12__ModuleInfoZ in app.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to 
see invocation)
--- errorlevel 1
any Ideas?

structure is
app.d
app.o
arsd/
         dom.d
         dom.o

-------------------
CODE
-------------------
struct KHR_registry
{

     string comment; // Not as xml comment  but a <comment> ... 
</comment>

     struct vendorid
     {
         string  name;
         string  id;
         string  comment;
     }
     vendorid[] vendorids;

     struct tag
     {
         string  name;
         string  author;
         string  contact;
     }
     tag[] tags;

     struct validity_type    // does not appear at this level but 
is common to commands and types
     {
         string[] str;

     }
     struct type
     {
         string name;            // inconsistanly in tag and 
content
         string requires;
         string parent;          // these are different things
         string parentName;      // ditto
         string content;         // <type ... > content </type>
         string category;
         bool returnedonly;

         validity_type validity;
         struct member
         {
             string typename;                    //name of the 
members type variable tag type
             string name;                        //name of the 
member variable
             string len;                         //companion 
member length variable for array pointers
             bool optional;                      //should generate 
as a default value
             bool noautovalidity;
             string enum_;

         }
         member[string] members;
     }
     type[string] types;

     struct enums
     {
         string name,comment, type, expand;      // expand is the 
C enum's Prefix e.g. VK_QUERY_TYPE
         struct enum_
         {
             string value, name, comment;
         }
         enum_[string] values;
     }
     enums[string] enumerations;
     struct command
     {
         string successcodes;
         string errorcodes;
         string returnType;
         string name;
         string content;

         struct param
         {
             string content;
             bool optional;
             string externsync;
             string len;
             size_t inderections;
             immutable invalidLen = "null-terminated";   // if len 
is this then it is not an array
                                                         // 
although this is inconsistant. sometimes as a len
                                                         // others 
in the validity
         }
         param[] params;
         validity_type validity;
         string queues, renderpass, cmdbufferlevel;
     }

     command[string] commands;
     struct feature
     {
         string api, name, number;

         /*
          <require comment="API version">
          <type name="VK_API_VERSION"/>
          <enum name="VK_VERSION_MAJOR"/>
          <command name="VK_VERSION_MINOR"/>
          <type name="VK_VERSION_PATCH"/>
          </require>*/
         struct require

         {
             string comment;
             string metaType; // type enum command see above 
variable tag type

             string name;


         }
         require requires;
     }
     struct extension
     {
         string name, number, supported;
         struct require
         {
             struct elem
             {
                 string name, content;
                 string metaType;
                 string offset, extends;
             }
         }
     }
     extension[] extensions;
}

KHR_registry regFromArsdDocument(Document doc)
{
     KHR_registry reg;
     size_t i;
     reg.comment   = 
doc.getElementsByTagName("comment")[0].innerText(); // only one 
comment
     reg.vendorids = doc.getElementsByTagName("vendorids")[0]
                             .getElementsByTagName("vendorid")
                             .map!(elem =>
                             {
                                 KHR_registry.vendorid vid;
                                 vid.name    = 
elem.getAttribute("name");
                                 vid.id      = 
elem.getAttribute("id");
                                 vid.comment = 
elem.getAttribute("comment");
                                 return vid;
                             })()
                             .array[].map!(a => a()).array;
     reg.tags      = doc.getElementsByTagName("tags")[0]
                             .getElementsByTagName("tag")
                             .map!(elem =>
                             {
                                 KHR_registry.tag t;
                                 t.name      = 
elem.getAttribute("name");
                                 t.author    = 
elem.getAttribute("author");
                                 t.contact   = 
elem.getAttribute("contact");
                                 return t;
                             })
                             .array.map!(a => a()).array[];
     /*reg.types   =*/
     doc.getElementsByTagName("types")[0] //associatve array 
assignment: can we do this as a range?
     .getElementsByTagName("type")
     .map!(elem =>
     {
         KHR_registry.type t;
         t.name = elem.getAttribute("name"); // for root types only
         if (t.name == null)
         {
             t.name          = 
elem.getElementsByTagName("name")[0].innerText;
             t.parentName    = 
elem.getElementsByTagName("type")[0].innerText;
         }
         t.requires = elem.getAttribute("requires");
         t.parent   = elem.getAttribute("parent");
         t.content  = elem.innerText;
         t.category = elem.getAttribute("catagory");
         t.returnedonly = elem.getAttribute("returnedonly") != 
null; // if it is present it is true
         if (elem.getElementsByTagName("validity"))
         {
             t.validity.str = 
elem.getElementsByTagName("validity")[0]
                                 .getElementsByTagName("usage")
                                 .map!( elem2 => 
elem2.innerText).array[];
         }

         if (t.category == "funcpointer")
         {
             t.parentName = null; // first <type> ... </type> is 
not actuall the parent type
             // we dont use the types in the signature because we 
use the inner text.
         }
         if (t.category == "struct")
         {   // TODO: preserve the XML comments
             /*t.members = */ elem.getElementsByTagName("name")
                                     .map!(elem2 =>
                                     {
                                         KHR_registry.type.member 
m;
                                         string name = 
elem2.getElementsByTagName("name")[0].innerText;
                                         m.name      = name;
                                         m.typename  = 
elem2.getElementsByTagName("type")[0].innerText;
                                         m.len       = 
elem2.getAttribute("len");
                                         m.enum_     = 
elem2.getAttribute("enum");               // for c-style array 
decls
                                                                   
                               // dont store text its the
                                                                   
                               //wrong way round for D fix it
                                                                   
                               //later
                                         m.optional  = 
elem2.getAttribute("optional") != null;   // if it is present it 
is true
                                         m.noautovalidity  = 
elem2.getAttribute("noautovalidity") != null;

                                         t.members[name] = m;
                                     });

         }

         reg.types[t.name] = t;
     });

     foreach(elem; doc.getElementsByTagName("enums")) // there are 
multiple <enums> elements
     {
         KHR_registry.enums e;
         e.name      = elem.getAttribute("name");
         e.comment   = elem.getAttribute("comment");
         e.expand    = elem.getAttribute("expand");

         foreach(elem2; elem.getElementsByTagName("enum"))
         {
             KHR_registry.enums.enum_ e2;
             e2.name      = elem.getAttribute("name");
             e2.comment   = elem.getAttribute("comment");
             e2.value    = elem.getAttribute("value");
             e.values[e2.name] = e2;

         }
         reg.enumerations[e.name] = e;
     }
     doc.getElementsByTagName("commands")[0] //associatve array 
assignment: can we do this as a range?
     .getElementsByTagName("command")
     .map!(elem =>
     {
         KHR_registry.command c;
         c.successcodes      = elem.getAttribute("successcodes");
         c.errorcodes        = elem.getAttribute("errorcodes");
         c.queues            = elem.getAttribute("queues");
         c.renderpass        = elem.getAttribute("renderpass");
         c.cmdbufferlevel    = elem.getAttribute("cmdbufferlevel");
         c.content           = elem.innerText;
         c.name              = 
elem.getElementsByTagName("proto")[0].getElementsByTagName("name")[0].innerText;
         c.returnType        = 
elem.getElementsByTagName("proto")[0].getElementsByTagName("type")[0].innerText;
         if (elem.getElementsByTagName("validity"))
         {
             c.validity.str = 
elem.getElementsByTagName("validity")[0]
                                 .getElementsByTagName("usage")
                                 .map!( elem2 => 
elem2.innerText).array[];
         }
         foreach(elem2; elem.getElementsByTagName("param"))
         {
             KHR_registry.command.param p;
             p.optional = elem2.getAttribute("optional") != null; 
// present = true
             p.externsync = elem2.getAttribute("externsync");
             p.len = elem2.getAttribute("len");

             c.params ~= p;
         }
     });

     return reg;
}




More information about the Digitalmars-d-learn mailing list