1 // Copyright (c) 2014-2019 The Khronos Group Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and/or associated documentation files (the "Materials"), 5 // to deal in the Materials without restriction, including without limitation 6 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 // and/or sell copies of the Materials, and to permit persons to whom the 8 // Materials are furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Materials. 12 // 13 // MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS 14 // STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND 15 // HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ 16 // 17 // THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 // FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS 23 // IN THE MATERIALS. 24 25 // 26 // Print headers for SPIR-V in several languages. 27 // 28 // To change the header information, change the C++-built database in doc.*. 29 // 30 // Then, use "spriv -h <language>" - e.g, spriv.{h,hpp,lua,py,etc}: 31 // replace the auto-generated header, or "spirv -H" to generate all 32 // supported language headers to predefined names in the current directory. 33 // 34 35 #include <string> 36 #include <sstream> 37 #include <fstream> 38 #include <cstring> 39 #include <cstdio> 40 #include <algorithm> 41 #include <memory> 42 #include <cctype> 43 #include <vector> 44 #include <utility> 45 46 #include "jsoncpp/dist/json/json.h" 47 48 #include "header.h" 49 #include "jsonToSpirv.h" 50 51 // snprintf and _snprintf are not quite the same, but close enough 52 // for our use. 53 #ifdef _MSC_VER 54 #pragma warning(disable:4996) 55 #define snprintf _snprintf 56 #endif 57 58 // This file converts SPIR-V definitions to an internal JSON 59 // representation, and then generates language specific 60 // data from that single internal form. 61 62 // Initially, the internal form is created from C++ data, 63 // though this can be changed to a JSON master in time. 64 65 namespace { 66 class TPrinter { 67 protected: 68 TPrinter(); 69 70 static const int DocMagicNumber = 0x07230203; 71 static const int DocVersion = 0x00010300; 72 static const int DocRevision = 6; 73 #define DocRevisionString "6" 74 static const std::string DocCopyright; 75 static const std::string DocComment1; 76 static const std::string DocComment2; 77 78 enum enumStyle_t { 79 enumNoMask, 80 enumCount, 81 enumShift, 82 enumMask, 83 enumHex, 84 }; 85 styleStr(enumStyle_t s)86 static std::string styleStr(enumStyle_t s) { 87 return s == enumShift ? "Shift" : 88 s == enumMask ? "Mask" : ""; 89 } 90 91 friend std::ostream& operator<<(std::ostream&, const TPrinter&); 92 93 virtual void printAll(std::ostream&) const; 94 virtual void printComments(std::ostream&) const; printPrologue(std::ostream &) const95 virtual void printPrologue(std::ostream&) const { } 96 virtual void printDefs(std::ostream&) const; printEpilogue(std::ostream &) const97 virtual void printEpilogue(std::ostream&) const { } 98 virtual void printMeta(std::ostream&) const; printTypes(std::ostream &) const99 virtual void printTypes(std::ostream&) const { } 100 101 virtual std::string escapeComment(const std::string& s) const; 102 103 // Default printComments() uses these comment strings commentBeg() const104 virtual std::string commentBeg() const { return ""; } commentEnd(bool isLast) const105 virtual std::string commentEnd(bool isLast) const { return ""; } commentBOL() const106 virtual std::string commentBOL() const { return ""; } commentEOL(bool isLast) const107 virtual std::string commentEOL(bool isLast) const { return ""; } 108 109 typedef std::pair<unsigned, std::string> valpair_t; 110 111 // for printing enum values enumBeg(const std::string &,enumStyle_t) const112 virtual std::string enumBeg(const std::string&, enumStyle_t) const { return ""; } enumEnd(const std::string &,enumStyle_t,bool isLast=false) const113 virtual std::string enumEnd(const std::string&, enumStyle_t, bool isLast = false) const { 114 return ""; 115 } enumFmt(const std::string &,const valpair_t &,enumStyle_t,bool isLast=false) const116 virtual std::string enumFmt(const std::string&, const valpair_t&, 117 enumStyle_t, bool isLast = false) const { 118 return ""; 119 } maxEnumFmt(const std::string &,const valpair_t &,enumStyle_t) const120 virtual std::string maxEnumFmt(const std::string&, const valpair_t&, 121 enumStyle_t) const { 122 return ""; 123 } 124 fmtConstInt(unsigned val,const std::string & name,const char * fmt,bool isLast=false) const125 virtual std::string fmtConstInt(unsigned val, const std::string& name, 126 const char* fmt, bool isLast = false) const { 127 return ""; 128 } 129 130 std::vector<valpair_t> getSortedVals(const Json::Value&) const; 131 indent(int count=1) const132 virtual std::string indent(int count = 1) const { 133 return std::string(count * 4, ' '); // default indent level = 4 134 } 135 fmtNum(const char * fmt,unsigned val)136 static std::string fmtNum(const char* fmt, unsigned val) { 137 char buff[16]; // ample for 8 hex digits + 0x 138 snprintf(buff, sizeof(buff), fmt, val); 139 buff[sizeof(buff)-1] = '\0'; // MSVC doesn't promise null termination 140 return buff; 141 } 142 143 static std::string fmtStyleVal(unsigned v, enumStyle_t style); 144 145 // If the enum value name would start with a sigit, prepend the enum name. 146 // E.g, "3D" -> "Dim3D". prependIfDigit(const std::string & ename,const std::string & vname)147 static std::string prependIfDigit(const std::string& ename, const std::string& vname) { 148 return (std::isdigit(vname[0]) ? ename : std::string("")) + vname; 149 } 150 151 void addComment(Json::Value& node, const std::string& str); 152 153 Json::Value spvRoot; // JSON SPIR-V data 154 }; 155 156 // Format value as mask or value fmtStyleVal(unsigned v,enumStyle_t style)157 std::string TPrinter::fmtStyleVal(unsigned v, enumStyle_t style) 158 { 159 switch (style) { 160 case enumMask: 161 return fmtNum("0x%08x", 1<<v); 162 case enumHex: 163 return fmtNum("0x%08x", v); 164 default: 165 return std::to_string(v); 166 } 167 } 168 169 const std::string TPrinter::DocCopyright = 170 "Copyright (c) 2014-2019 The Khronos Group Inc.\n" 171 "\n" 172 "Permission is hereby granted, free of charge, to any person obtaining a copy\n" 173 "of this software and/or associated documentation files (the \"Materials\"),\n" 174 "to deal in the Materials without restriction, including without limitation\n" 175 "the rights to use, copy, modify, merge, publish, distribute, sublicense,\n" 176 "and/or sell copies of the Materials, and to permit persons to whom the\n" 177 "Materials are furnished to do so, subject to the following conditions:\n" 178 "\n" 179 "The above copyright notice and this permission notice shall be included in\n" 180 "all copies or substantial portions of the Materials.\n" 181 "\n" 182 "MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS\n" 183 "STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND\n" 184 "HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ \n" 185 "\n" 186 "THE MATERIALS ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n" 187 "OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n" 188 "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n" 189 "THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n" 190 "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n" 191 "FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS\n" 192 "IN THE MATERIALS.\n"; 193 194 const std::string TPrinter::DocComment1 = 195 "This header is automatically generated by the same tool that creates\n" 196 "the Binary Section of the SPIR-V specification.\n"; 197 198 const std::string TPrinter::DocComment2 = 199 "Enumeration tokens for SPIR-V, in various styles:\n" 200 " C, C++, C++11, JSON, Lua, Python, C#, D\n" 201 "\n" 202 "- C will have tokens with a \"Spv\" prefix, e.g.: SpvSourceLanguageGLSL\n" 203 "- C++ will have tokens in the \"spv\" name space, e.g.: spv::SourceLanguageGLSL\n" 204 "- C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL\n" 205 "- Lua will use tables, e.g.: spv.SourceLanguage.GLSL\n" 206 "- Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL']\n" 207 "- C# will use enum classes in the Specification class located in the \"Spv\" namespace,\n" 208 " e.g.: Spv.Specification.SourceLanguage.GLSL\n" 209 "- D will have tokens under the \"spv\" module, e.g: spv.SourceLanguage.GLSL\n" 210 "\n" 211 "Some tokens act like mask values, which can be OR'd together,\n" 212 "while others are mutually exclusive. The mask-like ones have\n" 213 "\"Mask\" in their name, and a parallel enum that has the shift\n" 214 "amount (1 << x) for each corresponding enumerant.\n"; 215 216 // Construct TPrinter()217 TPrinter::TPrinter() 218 { 219 Json::Value& meta = spvRoot["spv"]["meta"]; 220 Json::Value& enums = spvRoot["spv"]["enum"]; 221 222 meta["MagicNumber"] = DocMagicNumber; 223 meta["Version"] = DocVersion; 224 meta["Revision"] = DocRevision; 225 meta["OpCodeMask"] = 0xffff; 226 meta["WordCountShift"] = 16; 227 228 int commentId = 0; 229 addComment(meta["Comment"][commentId++], DocCopyright); 230 addComment(meta["Comment"][commentId++], DocComment1); 231 addComment(meta["Comment"][commentId++], DocComment2); 232 233 for (int e = spv::OperandSource; e < spv::OperandOpcode; ++e) { 234 auto& enumSet = spv::OperandClassParams[e]; 235 const bool mask = enumSet.bitmask; 236 const std::string enumName = enumSet.codeName; 237 238 for (auto& enumRow : enumSet) { 239 std::string name = enumRow.name; 240 enums[e - spv::OperandSource]["Values"][name] = enumRow.value; 241 } 242 243 enums[e - spv::OperandSource]["Type"] = mask ? "Bit" : "Value"; 244 enums[e - spv::OperandSource]["Name"] = enumName; 245 } 246 247 // Instructions are in their own different table 248 { 249 auto& entry = enums[spv::OperandOpcode - spv::OperandSource]; 250 for (auto& enumRow : spv::InstructionDesc) { 251 std::string name = enumRow.name; 252 entry["Values"][name] = enumRow.value; 253 } 254 entry["Type"] = "Value"; 255 entry["Name"] = "Op"; 256 } 257 } 258 259 // Create comment addComment(Json::Value & node,const std::string & str)260 void TPrinter::addComment(Json::Value& node, const std::string& str) 261 { 262 std::istringstream cstream(str); 263 std::string cline; 264 265 int line = 0; 266 while (std::getline(cstream, cline)) // fmt each line 267 node[line++] = cline; 268 } 269 270 271 // Return a list of values sorted by enum value. The std::vector 272 // returned by value is okay in c++11 due to move semantics. 273 std::vector<TPrinter::valpair_t> getSortedVals(const Json::Value & p) const274 TPrinter::getSortedVals(const Json::Value& p) const 275 { 276 std::vector<valpair_t> values; 277 278 for (auto e = p.begin(); e != p.end(); ++e) 279 values.push_back(valpair_t(e->asUInt(), e.name())); 280 281 // Use a stable sort because we might have aliases, e.g. 282 // SubgropuBallot (might be in future core) vs. SubgroupBallotKHR. 283 std::stable_sort(values.begin(), values.end()); 284 285 return values; 286 } 287 288 // Escape comment characters if needed escapeComment(const std::string & s) const289 std::string TPrinter::escapeComment(const std::string& s) const { return s; } 290 291 // Format comments in language specific way printComments(std::ostream & out) const292 void TPrinter::printComments(std::ostream& out) const 293 { 294 const int commentCount = spvRoot["spv"]["meta"]["Comment"].size(); 295 int commentNum = 0; 296 297 for (const auto& comment : spvRoot["spv"]["meta"]["Comment"]) { 298 out << commentBeg(); 299 300 for (int line = 0; line < int(comment.size()); ++line) 301 out << commentBOL() << escapeComment(comment[line].asString()) << 302 commentEOL((line+1) == comment.size()) << std::endl; 303 304 out << commentEnd(++commentNum == commentCount) << std::endl; 305 } 306 } 307 308 // Format header metadata printMeta(std::ostream & out) const309 void TPrinter::printMeta(std::ostream& out) const 310 { 311 const Json::Value& meta = spvRoot["spv"]["meta"]; 312 313 const auto print = [&](const char* name, const char* fmt, bool isLast) { 314 out << fmtConstInt(meta[name].asUInt(), name, fmt, isLast); 315 }; 316 317 print("MagicNumber", "0x%08lx", false); 318 print("Version", "0x%08lx", false); 319 print("Revision", "%d", false); 320 print("OpCodeMask", "0x%04x", false); 321 print("WordCountShift", "%d", true); 322 } 323 324 // Format value definitions in language specific way printDefs(std::ostream & out) const325 void TPrinter::printDefs(std::ostream& out) const 326 { 327 const Json::Value& enums = spvRoot["spv"]["enum"]; 328 329 for (auto opClass = enums.begin(); opClass != enums.end(); ++opClass) { 330 const bool isMask = (*opClass)["Type"].asString() == "Bit"; 331 const auto opName = (*opClass)["Name"].asString(); 332 const auto opPrefix = opName == "Op" ? "" : opName; 333 334 for (enumStyle_t style = (isMask ? enumShift : enumCount); 335 style <= (isMask ? enumMask : enumCount); style = enumStyle_t(int(style)+1)) { 336 337 out << enumBeg(opName, style); 338 339 if (style == enumMask) 340 out << enumFmt(opPrefix, valpair_t(0, "MaskNone"), enumNoMask); 341 342 const auto sorted = getSortedVals((*opClass)["Values"]); 343 344 std::string maxEnum = maxEnumFmt(opName, valpair_t(0x7FFFFFFF, "Max"), enumHex); 345 346 bool printMax = (style != enumMask && maxEnum.size() > 0); 347 348 for (const auto& v : sorted) 349 out << enumFmt(opPrefix, v, style, !printMax && v.first == sorted.back().first); 350 351 if (printMax) 352 out << maxEnum; 353 354 auto nextOpClass = opClass; 355 out << enumEnd(opName, style, ++nextOpClass == enums.end()); 356 } 357 } 358 } 359 printAll(std::ostream & out) const360 void TPrinter::printAll(std::ostream& out) const 361 { 362 printComments(out); 363 printPrologue(out); 364 printTypes(out); 365 printMeta(out); 366 printDefs(out); 367 printEpilogue(out); 368 } 369 370 // Stream entire header to output operator <<(std::ostream & out,const TPrinter & p)371 std::ostream& operator<<(std::ostream& out, const TPrinter &p) 372 { 373 p.printAll(out); 374 return out; 375 } 376 377 // JSON printer. Rather than use the default printer, we supply our own so 378 // we can control the printing order within various containers. 379 class TPrinterJSON final : public TPrinter { 380 private: printPrologue(std::ostream & out) const381 void printPrologue(std::ostream& out) const override { out << "{\n" + indent() + "\"spv\":\n" + indent() + "{\n"; } printEpilogue(std::ostream & out) const382 void printEpilogue(std::ostream& out) const override { out << indent() + "}\n}\n"; } 383 escapeComment(const std::string & s) const384 std::string escapeComment(const std::string& s) const override { 385 std::string newStr; 386 for (auto c : s) { 387 if (c == '"') { 388 newStr += '\\'; 389 newStr += c; 390 } else { 391 newStr += c; 392 } 393 } 394 return newStr; 395 } 396 fmtConstInt(unsigned val,const std::string & name,const char * fmt,bool isLast) const397 std::string fmtConstInt(unsigned val, const std::string& name, 398 const char* fmt, bool isLast) const override { 399 return indent(3) + '"' + name + "\": " + fmtNum("%d", val) + (isLast ? "\n" : ",\n"); 400 } 401 printMeta(std::ostream & out) const402 void printMeta(std::ostream& out) const override 403 { 404 out << indent(2) + "\"meta\":\n" + indent(2) + "{\n"; 405 printComments(out); 406 TPrinter::printMeta(out); 407 out << indent(2) + "},\n"; 408 } 409 commentBeg() const410 std::string commentBeg() const override { return indent(4) + "[\n"; } commentEnd(bool isLast) const411 std::string commentEnd(bool isLast) const override { return indent(4) + (isLast ? "]" : "],"); } commentBOL() const412 std::string commentBOL() const override { return indent(5) + '"'; } commentEOL(bool isLast) const413 std::string commentEOL(bool isLast) const override { return (isLast ? "\"" : "\","); } 414 printComments(std::ostream & out) const415 void printComments(std::ostream& out) const override 416 { 417 out << indent(3) + "\"Comment\":\n" + indent(3) + "[\n"; 418 TPrinter::printComments(out); 419 out << indent(3) + "],\n"; 420 } 421 printDefs(std::ostream & out) const422 void printDefs(std::ostream& out) const override 423 { 424 out << indent(2) + "\"enum\":\n" + indent(2) + "[\n"; 425 TPrinter::printDefs(out); 426 out << indent(2) + "]\n"; 427 } 428 printAll(std::ostream & out) const429 void printAll(std::ostream& out) const override 430 { 431 printPrologue(out); 432 printMeta(out); 433 printDefs(out); 434 printEpilogue(out); 435 } 436 enumBeg(const std::string & s,enumStyle_t style) const437 std::string enumBeg(const std::string& s, enumStyle_t style) const override { 438 if (style == enumMask) 439 return ""; 440 return indent(3) + "{\n" + 441 indent(4) + "\"Name\": \"" + s + "\",\n" + 442 indent(4) + "\"Type\": " + (style == enumShift ? "\"Bit\"" : "\"Value\"") + ",\n" + 443 indent(4) + "\"Values\":\n" + 444 indent(4) + "{\n"; 445 } 446 enumEnd(const std::string & s,enumStyle_t style,bool isLast) const447 std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override { 448 if (style == enumMask) 449 return ""; 450 return indent(4) + "}\n" + 451 indent(3) + "}" + (isLast ? "" : ",") + "\n"; 452 } 453 enumFmt(const std::string & s,const valpair_t & v,enumStyle_t style,bool isLast) const454 std::string enumFmt(const std::string& s, const valpair_t& v, 455 enumStyle_t style, bool isLast) const override { 456 if (style == enumMask || style == enumNoMask) 457 return ""; 458 return indent(5) + '"' + prependIfDigit(s, v.second) + "\": " + fmtNum("%d", v.first) + 459 (isLast ? "\n" : ",\n"); 460 } 461 }; 462 463 // base for C and C++ 464 class TPrinterCBase : public TPrinter { 465 protected: printPrologue(std::ostream & out) const466 virtual void printPrologue(std::ostream& out) const override { 467 out << "#ifndef spirv_" << headerGuardSuffix() << std::endl 468 << "#define spirv_" << headerGuardSuffix() << std::endl 469 << std::endl; 470 } 471 printMeta(std::ostream & out) const472 void printMeta(std::ostream& out) const override { 473 out << "#define SPV_VERSION 0x" << std::hex << DocVersion << std::dec << "\n"; 474 out << "#define SPV_REVISION " << DocRevision << "\n"; 475 out << "\n"; 476 477 return TPrinter::printMeta(out); 478 } 479 printEpilogue(std::ostream & out) const480 virtual void printEpilogue(std::ostream& out) const override { 481 out << "#endif // #ifndef spirv_" << headerGuardSuffix() << std::endl; 482 } 483 printTypes(std::ostream & out) const484 virtual void printTypes(std::ostream& out) const override { 485 out << "typedef unsigned int " << pre() << "Id;\n\n"; 486 } 487 fmtConstInt(unsigned val,const std::string & name,const char * fmt,bool isLast) const488 virtual std::string fmtConstInt(unsigned val, const std::string& name, 489 const char* fmt, bool isLast) const override 490 { 491 return std::string("static const unsigned int ") + pre() + name + 492 " = " + fmtNum(fmt, val) + (isLast ? ";\n\n" : ";\n"); 493 } 494 pre() const495 virtual std::string pre() const { return ""; } // C name prefix 496 virtual std::string headerGuardSuffix() const = 0; 497 }; 498 499 // C printer 500 class TPrinterC final : public TPrinterCBase { 501 private: commentBeg() const502 std::string commentBeg() const override { return "/*\n"; } commentEnd(bool isLast) const503 std::string commentEnd(bool isLast) const override { return "*/\n"; } commentBOL() const504 std::string commentBOL() const override { return "** "; } 505 enumBeg(const std::string & s,enumStyle_t style) const506 std::string enumBeg(const std::string& s, enumStyle_t style) const override { 507 return std::string("typedef enum ") + pre() + s + styleStr(style) + "_ {\n"; 508 } 509 enumEnd(const std::string & s,enumStyle_t style,bool isLast) const510 std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override { 511 return "} " + pre() + s + styleStr(style) + ";\n\n"; 512 } 513 enumFmt(const std::string & s,const valpair_t & v,enumStyle_t style,bool isLast) const514 std::string enumFmt(const std::string& s, const valpair_t& v, 515 enumStyle_t style, bool isLast) const override { 516 return indent() + pre() + s + v.second + styleStr(style) + " = " + fmtStyleVal(v.first, style) + ",\n"; 517 } 518 maxEnumFmt(const std::string & s,const valpair_t & v,enumStyle_t style) const519 std::string maxEnumFmt(const std::string& s, const valpair_t& v, 520 enumStyle_t style) const override { 521 return enumFmt(s, v, style, true); 522 } 523 pre() const524 std::string pre() const override { return "Spv"; } // C name prefix headerGuardSuffix() const525 std::string headerGuardSuffix() const override { return "H"; } 526 }; 527 528 // C++ printer 529 class TPrinterCPP : public TPrinterCBase { 530 private: printPrologue(std::ostream & out) const531 void printPrologue(std::ostream& out) const override { 532 TPrinterCBase::printPrologue(out); 533 out << "namespace spv {\n\n"; 534 } 535 printEpilogue(std::ostream & out) const536 void printEpilogue(std::ostream& out) const override { 537 const Json::Value& enums = spvRoot["spv"]["enum"]; 538 539 // Create overloaded operator| for mask types 540 out << "// Overload operator| for mask bit combining\n\n"; 541 542 for (auto opClass = enums.begin(); opClass != enums.end(); ++opClass) { 543 const bool isMask = (*opClass)["Type"].asString() == "Bit"; 544 const auto opName = (*opClass)["Name"].asString(); 545 546 if (isMask) { 547 const auto typeName = opName + styleStr(enumMask); 548 549 out << "inline " + typeName + " operator|(" + typeName + " a, " + typeName + " b) { return " + 550 typeName + "(unsigned(a) | unsigned(b)); }\n"; 551 } 552 } 553 554 out << "\n} // end namespace spv\n\n"; 555 TPrinterCBase::printEpilogue(out); 556 } 557 commentBOL() const558 std::string commentBOL() const override { return "// "; } 559 560 enumBeg(const std::string & s,enumStyle_t style) const561 virtual std::string enumBeg(const std::string& s, enumStyle_t style) const override { 562 return std::string("enum ") + s + styleStr(style) + " {\n"; 563 } 564 enumEnd(const std::string & s,enumStyle_t style,bool isLast) const565 std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override { 566 return "};\n\n"; 567 } 568 enumFmt(const std::string & s,const valpair_t & v,enumStyle_t style,bool isLast) const569 virtual std::string enumFmt(const std::string& s, const valpair_t& v, 570 enumStyle_t style, bool isLast) const override { 571 return indent() + s + v.second + styleStr(style) + " = " + fmtStyleVal(v.first, style) + ",\n"; 572 } 573 maxEnumFmt(const std::string & s,const valpair_t & v,enumStyle_t style) const574 virtual std::string maxEnumFmt(const std::string& s, const valpair_t& v, 575 enumStyle_t style) const override { 576 return enumFmt(s, v, style, true); 577 } 578 579 // The C++ and C++11 headers define types with the same name. So they 580 // should use the same header guard. headerGuardSuffix() const581 std::string headerGuardSuffix() const override { return "HPP"; } 582 583 std::string operators; 584 }; 585 586 // C++11 printer (uses enum classes) 587 class TPrinterCPP11 final : public TPrinterCPP { 588 private: enumBeg(const std::string & s,enumStyle_t style) const589 std::string enumBeg(const std::string& s, enumStyle_t style) const override { 590 return std::string("enum class ") + s + styleStr(style) + " : unsigned {\n"; 591 } 592 enumFmt(const std::string & s,const valpair_t & v,enumStyle_t style,bool isLast) const593 std::string enumFmt(const std::string& s, const valpair_t& v, 594 enumStyle_t style, bool isLast) const override { 595 return indent() + prependIfDigit(s, v.second) + " = " + fmtStyleVal(v.first, style) + ",\n"; 596 } 597 maxEnumFmt(const std::string & s,const valpair_t & v,enumStyle_t style) const598 std::string maxEnumFmt(const std::string& s, const valpair_t& v, 599 enumStyle_t style) const override { 600 return enumFmt(s, v, style, true); 601 } 602 headerGuardSuffix() const603 std::string headerGuardSuffix() const override { return "HPP"; } 604 }; 605 606 // LUA printer 607 class TPrinterLua final : public TPrinter { 608 private: printPrologue(std::ostream & out) const609 void printPrologue(std::ostream& out) const override { out << "spv = {\n"; } 610 printEpilogue(std::ostream & out) const611 void printEpilogue(std::ostream& out) const override { out << "}\n"; } 612 commentBOL() const613 std::string commentBOL() const override { return "-- "; } 614 enumBeg(const std::string & s,enumStyle_t style) const615 std::string enumBeg(const std::string& s, enumStyle_t style) const override { 616 return indent() + s + styleStr(style) + " = {\n"; 617 } 618 enumEnd(const std::string & s,enumStyle_t style,bool isLast) const619 std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override { 620 return indent() + "},\n\n"; 621 } 622 enumFmt(const std::string & s,const valpair_t & v,enumStyle_t style,bool isLast) const623 std::string enumFmt(const std::string& s, const valpair_t& v, 624 enumStyle_t style, bool isLast) const override { 625 return indent(2) + prependIfDigit(s, v.second) + " = " + fmtStyleVal(v.first, style) + ",\n"; 626 } 627 fmtConstInt(unsigned val,const std::string & name,const char * fmt,bool isLast) const628 virtual std::string fmtConstInt(unsigned val, const std::string& name, 629 const char* fmt, bool isLast) const override 630 { 631 return indent() + name + " = " + fmtNum(fmt, val) + (isLast ? ",\n\n" : ",\n"); 632 } 633 }; 634 635 // Python printer 636 class TPrinterPython final : public TPrinter { 637 private: printPrologue(std::ostream & out) const638 void printPrologue(std::ostream& out) const override { out << "spv = {\n"; } 639 printEpilogue(std::ostream & out) const640 void printEpilogue(std::ostream& out) const override { out << "}\n"; } 641 commentBOL() const642 std::string commentBOL() const override { return "# "; } 643 enumBeg(const std::string & s,enumStyle_t style) const644 std::string enumBeg(const std::string& s, enumStyle_t style) const override { 645 return indent() + "'" + s + styleStr(style) + "'" + " : {\n"; 646 } 647 enumEnd(const std::string & s,enumStyle_t style,bool isLast) const648 std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override { 649 return indent() + "},\n\n"; 650 } 651 enumFmt(const std::string & s,const valpair_t & v,enumStyle_t style,bool isLast) const652 std::string enumFmt(const std::string& s, const valpair_t& v, 653 enumStyle_t style, bool isLast) const override { 654 return indent(2) + "'" + prependIfDigit(s, v.second) + "'" + " : " + fmtStyleVal(v.first, style) + ",\n"; 655 } 656 fmtConstInt(unsigned val,const std::string & name,const char * fmt,bool isLast) const657 std::string fmtConstInt(unsigned val, const std::string& name, 658 const char* fmt, bool isLast) const override 659 { 660 return indent() + "'" + name + "'" + " : " + fmtNum(fmt, val) + (isLast ? ",\n\n" : ",\n"); 661 } 662 }; 663 664 // C# printer 665 class TPrinterCSharp final : public TPrinter { 666 private: commentBOL() const667 std::string commentBOL() const override { return "// "; } 668 printPrologue(std::ostream & out) const669 void printPrologue(std::ostream& out) const override { 670 out << "namespace Spv\n{\n\n"; 671 out << indent() << "public static class Specification\n"; 672 out << indent() << "{\n"; 673 } 674 printEpilogue(std::ostream & out) const675 void printEpilogue(std::ostream& out) const override { 676 out << indent() << "}\n"; 677 out << "}\n"; 678 } 679 enumBeg(const std::string & s,enumStyle_t style) const680 std::string enumBeg(const std::string& s, enumStyle_t style) const override { 681 return indent(2) + "public enum " + s + styleStr(style) + "\n" + indent(2) + "{\n"; 682 } 683 enumEnd(const std::string & s,enumStyle_t style,bool isLast) const684 std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override { 685 return indent(2) + "}" + + (isLast ? "\n" : "\n\n"); 686 } 687 enumFmt(const std::string & s,const valpair_t & v,enumStyle_t style,bool isLast) const688 std::string enumFmt(const std::string& s, const valpair_t& v, 689 enumStyle_t style, bool isLast) const override { 690 return indent(3) + prependIfDigit(s, v.second) + " = " + fmtStyleVal(v.first, style) + ",\n"; 691 } 692 fmtConstInt(unsigned val,const std::string & name,const char * fmt,bool isLast) const693 std::string fmtConstInt(unsigned val, const std::string& name, 694 const char* fmt, bool isLast) const override { 695 return indent(2) + std::string("public const uint ") + name + 696 " = " + fmtNum(fmt, val) + (isLast ? ";\n\n" : ";\n"); 697 } 698 }; 699 700 // D printer 701 class TPrinterD final : public TPrinter { 702 private: commentBeg() const703 std::string commentBeg() const override { return "/+\n"; } commentBOL() const704 std::string commentBOL() const override { return " + "; } commentEnd(bool isLast) const705 std::string commentEnd(bool isLast) const override { return " +/\n"; } 706 printPrologue(std::ostream & out) const707 void printPrologue(std::ostream& out) const override { 708 out << "module spv;\n\n"; 709 } 710 printEpilogue(std::ostream & out) const711 void printEpilogue(std::ostream& out) const override { 712 } 713 enumBeg(const std::string & s,enumStyle_t style) const714 std::string enumBeg(const std::string& s, enumStyle_t style) const override { 715 return "enum " + s + styleStr(style) + " : uint\n{\n"; 716 } 717 enumEnd(const std::string & s,enumStyle_t style,bool isLast) const718 std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override { 719 return std::string("}\n\n"); 720 } 721 enumFmt(const std::string & s,const valpair_t & v,enumStyle_t style,bool isLast) const722 std::string enumFmt(const std::string& s, const valpair_t& v, 723 enumStyle_t style, bool isLast) const override { 724 return indent() + prependIfDigit("_", v.second) + " = " + fmtStyleVal(v.first, style) + ",\n"; 725 } 726 fmtConstInt(unsigned val,const std::string & name,const char * fmt,bool isLast) const727 std::string fmtConstInt(unsigned val, const std::string& name, 728 const char* fmt, bool isLast) const override { 729 return std::string("enum uint ") + name + 730 " = " + fmtNum(fmt, val) + (isLast ? ";\n\n" : ";\n"); 731 } 732 }; 733 734 } // namespace 735 736 namespace spv { PrintAllHeaders()737 void PrintAllHeaders() 738 { 739 // TODO: Once MSVC 2012 is no longer a factor, use brace initializers here 740 std::vector<std::pair<TLanguage, std::string>> langInfo; 741 742 langInfo.push_back(std::make_pair(ELangC, "spirv.h")); 743 langInfo.push_back(std::make_pair(ELangCPP, "spirv.hpp")); 744 langInfo.push_back(std::make_pair(ELangCPP11, "spirv.hpp11")); 745 langInfo.push_back(std::make_pair(ELangJSON, "spirv.json")); 746 langInfo.push_back(std::make_pair(ELangLua, "spirv.lua")); 747 langInfo.push_back(std::make_pair(ELangPython, "spirv.py")); 748 langInfo.push_back(std::make_pair(ELangCSharp, "spirv.cs")); 749 langInfo.push_back(std::make_pair(ELangD, "spv.d")); 750 751 for (const auto& lang : langInfo) { 752 std::ofstream out(lang.second, std::ios::out); 753 754 if ((out.rdstate() & std::ifstream::failbit)) { 755 std::cerr << "Unable to open file: " << lang.second << std::endl; 756 } else { 757 PrintHeader(lang.first, out); 758 } 759 } 760 } 761 762 // Print header for given language to given output stream PrintHeader(TLanguage lang,std::ostream & out)763 void PrintHeader(TLanguage lang, std::ostream& out) 764 { 765 typedef std::unique_ptr<TPrinter> TPrinterPtr; 766 TPrinterPtr p; 767 768 switch (lang) { 769 case ELangC: p = TPrinterPtr(new TPrinterC); break; 770 case ELangCPP: p = TPrinterPtr(new TPrinterCPP); break; 771 case ELangCPP11: p = TPrinterPtr(new TPrinterCPP11); break; 772 case ELangJSON: p = TPrinterPtr(new TPrinterJSON); break; 773 case ELangLua: p = TPrinterPtr(new TPrinterLua); break; 774 case ELangPython: p = TPrinterPtr(new TPrinterPython); break; 775 case ELangCSharp: p = TPrinterPtr(new TPrinterCSharp); break; 776 case ELangD: p = TPrinterPtr(new TPrinterD); break; 777 case ELangAll: PrintAllHeaders(); break; 778 default: 779 std::cerr << "Unknown language." << std::endl; 780 return; 781 } 782 783 // Print the data in the requested format 784 if (p) 785 out << *p << std::endl; 786 787 // object is auto-deleted 788 } 789 790 } // namespace spv 791