| 
1479
 | 
     1 import std/strtabs
 | 
| 
 | 
     2 import std/xmltree
 | 
| 
 | 
     3 import std/tables
 | 
| 
 | 
     4 import std/options
 | 
| 
 | 
     5 import std/sequtils
 | 
| 
 | 
     6 import std/strutils
 | 
| 
 | 
     7 import std/strformat
 | 
| 
 | 
     8 import std/xmlparser
 | 
| 
 | 
     9 import std/os
 | 
| 
 | 
    10 import std/paths
 | 
| 
 | 
    11 
 | 
| 
 | 
    12 # helpers
 | 
| 
 | 
    13 func smartParseInt(value: string): int =
 | 
| 
 | 
    14   if value.startsWith("0x"):
 | 
| 
 | 
    15     parseHexInt(value)
 | 
| 
 | 
    16   else:
 | 
| 
 | 
    17     parseInt(value)
 | 
| 
 | 
    18 
 | 
| 
 | 
    19 const TYPEMAP = {
 | 
| 
 | 
    20   "void": "void",
 | 
| 
 | 
    21   "char": "char",
 | 
| 
 | 
    22   "float": "float32",
 | 
| 
 | 
    23   "double": "float64",
 | 
| 
 | 
    24   "int8_t": "int8",
 | 
| 
 | 
    25   "uint8_t": "uint8",
 | 
| 
 | 
    26   "int16_t": "int16",
 | 
| 
 | 
    27   "uint16_t": "uint16",
 | 
| 
 | 
    28   "int32_t": "int32",
 | 
| 
 | 
    29   "uint32_t": "uint32",
 | 
| 
 | 
    30   "uint64_t": "uint64",
 | 
| 
 | 
    31   "int64_t": "int64",
 | 
| 
 | 
    32   "size_t": "csize_t",
 | 
| 
 | 
    33   "int": "cint",
 | 
| 
 | 
    34   "void*": "pointer",
 | 
| 
 | 
    35   "char*": "cstring",
 | 
| 
 | 
    36   "ptr char": "cstring",
 | 
| 
 | 
    37   "ptr void": "pointer",
 | 
| 
 | 
    38     # "VK_DEFINE_HANDLE": "VkHandle", # not required, can directly defined as a distinct pointer, (in C is a pointer to an empty struct type)
 | 
| 
 | 
    39     # "VK_DEFINE_NON_DISPATCHABLE_HANDLE": "VkNonDispatchableHandle", # same here
 | 
| 
 | 
    40 }.toTable
 | 
| 
 | 
    41 
 | 
| 
 | 
    42 # load xml
 | 
| 
 | 
    43 let xml = (system.currentSourcePath.parentDir() / "vk.xml").loadXml()
 | 
| 
 | 
    44 let platforms = xml.findAll("platforms")[0]
 | 
| 
 | 
    45 let types = xml.findAll("types")[0]
 | 
| 
 | 
    46 let xmlenums = xml.findAll("enums")
 | 
| 
 | 
    47 let commands = xml.findAll("commands")[0]
 | 
| 
 | 
    48 let features = xml.findAll("feature") # features has extends="<ENUM>"
 | 
| 
 | 
    49 let extensions = xml.findAll("extensions")[0] # extensions has extends="<ENUM>"
 | 
| 
 | 
    50 let formats = xml.findAll("formats")[0]
 | 
| 
 | 
    51 
 | 
| 
 | 
    52 # gather all enums
 | 
| 
 | 
    53 
 | 
| 
 | 
    54 type
 | 
| 
 | 
    55   EnumEntry = object
 | 
| 
 | 
    56     name: string
 | 
| 
 | 
    57     value: string
 | 
| 
 | 
    58 
 | 
| 
 | 
    59   EnumDef = object
 | 
| 
 | 
    60     name: string
 | 
| 
 | 
    61     values: seq[EnumEntry]
 | 
| 
 | 
    62     isBitmask: bool
 | 
| 
 | 
    63 
 | 
| 
 | 
    64   ConstantDef = object
 | 
| 
 | 
    65     name: string
 | 
| 
 | 
    66     datatype: string
 | 
| 
 | 
    67     value: string
 | 
| 
 | 
    68 
 | 
| 
 | 
    69 var consts: seq[ConstantDef]
 | 
| 
 | 
    70 var enums: Table[string, EnumDef]
 | 
| 
 | 
    71 
 | 
| 
 | 
    72 func addValue(edef: var EnumDef, n: XmlNode) =
 | 
| 
 | 
    73   if n.attr("deprecated") != "aliased" and n.attr("alias") == "":
 | 
| 
 | 
    74     if n.attr("name") in edef.values.mapIt(it.name):
 | 
| 
 | 
    75       return
 | 
| 
 | 
    76     if n.attr("name").endsWith("_EXT") and
 | 
| 
 | 
    77         n.attr("name")[0 ..< ^4] in edef.values.mapIt(it.name):
 | 
| 
 | 
    78       return
 | 
| 
 | 
    79 
 | 
| 
 | 
    80     var value = ""
 | 
| 
 | 
    81     if n.attr("value") != "":
 | 
| 
 | 
    82       value = n.attr("value")
 | 
| 
 | 
    83     elif n.attr("bitpos") != "":
 | 
| 
 | 
    84       value = $(1 shl parseInt(n.attr("bitpos")))
 | 
| 
 | 
    85     elif n.attr("offset") != "":
 | 
| 
 | 
    86       var enumBase = 1000000000
 | 
| 
 | 
    87       if n.attr("extnumber") != "":
 | 
| 
 | 
    88         enumBase += (smartParseInt(n.attr("extnumber")) - 1) * 1000
 | 
| 
 | 
    89       var v = smartParseInt(n.attr("offset")) + enumBase
 | 
| 
 | 
    90       if n.attr("dir") == "-":
 | 
| 
 | 
    91         v = -v
 | 
| 
 | 
    92       value = $(v)
 | 
| 
 | 
    93 
 | 
| 
 | 
    94     edef.values.add EnumEntry(name: n.attr("name"), value: value)
 | 
| 
 | 
    95 
 | 
| 
 | 
    96 for e in xmlenums:
 | 
| 
 | 
    97   if e.attr("type") == "constants":
 | 
| 
 | 
    98     for c in e.findAll("enum"):
 | 
| 
 | 
    99       var value = c.attr("value").strip(chars = {'(', ')'})
 | 
| 
 | 
   100       consts.add ConstantDef(
 | 
| 
 | 
   101         name: c.attr("name"), datatype: TYPEMAP[c.attr("type")], value: value
 | 
| 
 | 
   102       )
 | 
| 
 | 
   103   elif e.attr("type") == "enum":
 | 
| 
 | 
   104     var edef = EnumDef(name: e.attr("name"), isBitmask: false)
 | 
| 
 | 
   105     for ee in e.findAll("enum"):
 | 
| 
 | 
   106       edef.addValue(ee)
 | 
| 
 | 
   107     enums[edef.name] = edef
 | 
| 
 | 
   108   elif e.attr("type") == "bitmask":
 | 
| 
 | 
   109     var edef = EnumDef(name: e.attr("name"), isBitmask: true)
 | 
| 
 | 
   110     for ee in e.findAll("enum"):
 | 
| 
 | 
   111       edef.addValue(ee)
 | 
| 
 | 
   112     enums[edef.name] = edef
 | 
| 
 | 
   113 
 | 
| 
 | 
   114 for f in features:
 | 
| 
 | 
   115   for extendenum in f.findAll("enum"):
 | 
| 
 | 
   116     if extendenum.attr("extends") != "":
 | 
| 
 | 
   117       enums[extendenum.attr("extends")].addValue(extendenum)
 | 
| 
 | 
   118 
 | 
| 
 | 
   119 for extension in extensions.findAll("extension"):
 | 
| 
 | 
   120   let extNum = extension.attr("number")
 | 
| 
 | 
   121   for extendenum in extension.findAll("enum"):
 | 
| 
 | 
   122     if extendenum.attr("extends") != "":
 | 
| 
 | 
   123       if extendenum.attr("extnumber") == "":
 | 
| 
 | 
   124         extendenum.attrs["extnumber"] = extNum
 | 
| 
 | 
   125       enums[extendenum.attr("extends")].addValue(extendenum)
 | 
| 
 | 
   126 
 | 
| 
 | 
   127 # generate core types ===============================================================================
 | 
| 
 | 
   128 # preamble, much easier to hardcode than to generate from xml
 | 
| 
 | 
   129 echo """
 | 
| 
 | 
   130 when defined(linux):
 | 
| 
 | 
   131   include ./platform/xlib
 | 
| 
 | 
   132 when defined(windows):
 | 
| 
 | 
   133   include ./platform/win32
 | 
| 
 | 
   134 
 | 
| 
 | 
   135 func VK_MAKE_API_VERSION*(
 | 
| 
 | 
   136     variant: uint32, major: uint32, minor: uint32, patch: uint32
 | 
| 
 | 
   137 ): uint32 {.compileTime.} =
 | 
| 
 | 
   138   (variant shl 29) or (major shl 22) or (minor shl 12) or patch
 | 
| 
 | 
   139 
 | 
| 
 | 
   140 
 | 
| 
 | 
   141 """
 | 
| 
 | 
   142 
 | 
| 
 | 
   143 echo "type"
 | 
| 
 | 
   144 
 | 
| 
 | 
   145 for t in types:
 | 
| 
 | 
   146   if t.attr("deprecated") == "true":
 | 
| 
 | 
   147     continue
 | 
| 
 | 
   148   echo t
 | 
| 
 | 
   149 echo ""
 | 
| 
 | 
   150 
 | 
| 
 | 
   151 # generate consts ===============================================================================
 | 
| 
 | 
   152 echo "const"
 | 
| 
 | 
   153 for c in consts:
 | 
| 
 | 
   154   var value = c.value
 | 
| 
 | 
   155   if value.endsWith("U"):
 | 
| 
 | 
   156     value = value[0 ..^ 2] & "'u32"
 | 
| 
 | 
   157   elif value.endsWith("ULL"):
 | 
| 
 | 
   158     value = value[0 ..^ 4] & "'u64"
 | 
| 
 | 
   159   if value[0] == '~':
 | 
| 
 | 
   160     value = "not " & value[1 ..^ 1]
 | 
| 
 | 
   161   echo &"  {c.name}*: {c.datatype} = {value}"
 | 
| 
 | 
   162 echo ""
 | 
| 
 | 
   163 
 | 
| 
 | 
   164 # generate enums ===============================================================================
 | 
| 
 | 
   165 echo "type"
 | 
| 
 | 
   166 for edef in enums.values():
 | 
| 
 | 
   167   if edef.values.len > 0:
 | 
| 
 | 
   168     echo &"  {edef.name}* {{.size: 4.}} = enum"
 | 
| 
 | 
   169     for ee in edef.values:
 | 
| 
 | 
   170       echo &"    {ee.name} = {ee.value}"
 | 
| 
 | 
   171 echo ""
 |