| 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 "" |