1 // Copyright (c) 2014-2018 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 = 1; 73 #define DocRevisionString "1" 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-2018 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\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 "\n" 208 "Some tokens act like mask values, which can be OR'd together,\n" 209 "while others are mutually exclusive. The mask-like ones have\n" 210 "\"Mask\" in their name, and a parallel enum that has the shift\n" 211 "amount (1 << x) for each corresponding enumerant.\n"; 212 213 // Construct TPrinter()214 TPrinter::TPrinter() 215 { 216 Json::Value& meta = spvRoot["spv"]["meta"]; 217 Json::Value& enums = spvRoot["spv"]["enum"]; 218 219 meta["MagicNumber"] = DocMagicNumber; 220 meta["Version"] = DocVersion; 221 meta["Revision"] = DocRevision; 222 meta["OpCodeMask"] = 0xffff; 223 meta["WordCountShift"] = 16; 224 225 int commentId = 0; 226 addComment(meta["Comment"][commentId++], DocCopyright); 227 addComment(meta["Comment"][commentId++], DocComment1); 228 addComment(meta["Comment"][commentId++], DocComment2); 229 230 for (int e = spv::OperandSource; e < spv::OperandOpcode; ++e) { 231 auto& enumSet = spv::OperandClassParams[e]; 232 const bool mask = enumSet.bitmask; 233 const std::string enumName = enumSet.codeName; 234 235 for (auto& enumRow : enumSet) { 236 std::string name = enumRow.name; 237 enums[e - spv::OperandSource]["Values"][name] = enumRow.value; 238 } 239 240 enums[e - spv::OperandSource]["Type"] = mask ? "Bit" : "Value"; 241 enums[e - spv::OperandSource]["Name"] = enumName; 242 } 243 244 // Instructions are in their own different table 245 { 246 auto& entry = enums[spv::OperandOpcode - spv::OperandSource]; 247 for (auto& enumRow : spv::InstructionDesc) { 248 std::string name = enumRow.name; 249 entry["Values"][name] = enumRow.value; 250 } 251 entry["Type"] = "Value"; 252 entry["Name"] = "Op"; 253 } 254 } 255 256 // Create comment addComment(Json::Value & node,const std::string & str)257 void TPrinter::addComment(Json::Value& node, const std::string& str) 258 { 259 std::istringstream cstream(str); 260 std::string cline; 261 262 int line = 0; 263 while (std::getline(cstream, cline)) // fmt each line 264 node[line++] = cline; 265 } 266 267 268 // Return a list of values sorted by enum value. The std::vector 269 // returned by value is okay in c++11 due to move semantics. 270 std::vector<TPrinter::valpair_t> getSortedVals(const Json::Value & p) const271 TPrinter::getSortedVals(const Json::Value& p) const 272 { 273 std::vector<valpair_t> values; 274 275 for (auto e = p.begin(); e != p.end(); ++e) 276 values.push_back(valpair_t(e->asUInt(), e.name())); 277 278 // Use a stable sort because we might have aliases, e.g. 279 // SubgropuBallot (might be in future core) vs. SubgroupBallotKHR. 280 std::stable_sort(values.begin(), values.end()); 281 282 return values; 283 } 284 285 // Escape comment characters if needed escapeComment(const std::string & s) const286 std::string TPrinter::escapeComment(const std::string& s) const { return s; } 287 288 // Format comments in language specific way printComments(std::ostream & out) const289 void TPrinter::printComments(std::ostream& out) const 290 { 291 const int commentCount = spvRoot["spv"]["meta"]["Comment"].size(); 292 int commentNum = 0; 293 294 for (const auto& comment : spvRoot["spv"]["meta"]["Comment"]) { 295 out << commentBeg(); 296 297 for (int line = 0; line < int(comment.size()); ++line) 298 out << commentBOL() << escapeComment(comment[line].asString()) << 299 commentEOL((line+1) == comment.size()) << std::endl; 300 301 out << commentEnd(++commentNum == commentCount) << std::endl; 302 } 303 } 304 305 // Format header metadata printMeta(std::ostream & out) const306 void TPrinter::printMeta(std::ostream& out) const 307 { 308 const Json::Value& meta = spvRoot["spv"]["meta"]; 309 310 const auto print = [&](const char* name, const char* fmt, bool isLast) { 311 out << fmtConstInt(meta[name].asUInt(), name, fmt, isLast); 312 }; 313 314 print("MagicNumber", "0x%08lx", false); 315 print("Version", "0x%08lx", false); 316 print("Revision", "%d", false); 317 print("OpCodeMask", "0x%04x", false); 318 print("WordCountShift", "%d", true); 319 } 320 321 // Format value definitions in language specific way printDefs(std::ostream & out) const322 void TPrinter::printDefs(std::ostream& out) const 323 { 324 const Json::Value& enums = spvRoot["spv"]["enum"]; 325 326 for (auto opClass = enums.begin(); opClass != enums.end(); ++opClass) { 327 const bool isMask = (*opClass)["Type"].asString() == "Bit"; 328 const auto opName = (*opClass)["Name"].asString(); 329 const auto opPrefix = opName == "Op" ? "" : opName; 330 331 for (enumStyle_t style = (isMask ? enumShift : enumCount); 332 style <= (isMask ? enumMask : enumCount); style = enumStyle_t(int(style)+1)) { 333 334 out << enumBeg(opName, style); 335 336 if (style == enumMask) 337 out << enumFmt(opPrefix, valpair_t(0, "MaskNone"), enumNoMask); 338 339 const auto sorted = getSortedVals((*opClass)["Values"]); 340 341 std::string maxEnum = maxEnumFmt(opName, valpair_t(0x7FFFFFFF, "Max"), enumHex); 342 343 bool printMax = (style != enumMask && maxEnum.size() > 0); 344 345 for (const auto& v : sorted) 346 out << enumFmt(opPrefix, v, style, !printMax && v.first == sorted.back().first); 347 348 if (printMax) 349 out << maxEnum; 350 351 auto nextOpClass = opClass; 352 out << enumEnd(opName, style, ++nextOpClass == enums.end()); 353 } 354 } 355 } 356 printAll(std::ostream & out) const357 void TPrinter::printAll(std::ostream& out) const 358 { 359 printComments(out); 360 printPrologue(out); 361 printTypes(out); 362 printMeta(out); 363 printDefs(out); 364 printEpilogue(out); 365 } 366 367 // Stream entire header to output operator <<(std::ostream & out,const TPrinter & p)368 std::ostream& operator<<(std::ostream& out, const TPrinter &p) 369 { 370 p.printAll(out); 371 return out; 372 } 373 374 // JSON printer. Rather than use the default printer, we supply our own so 375 // we can control the printing order within various containers. 376 class TPrinterJSON final : public TPrinter { 377 private: printPrologue(std::ostream & out) const378 void printPrologue(std::ostream& out) const override { out << "{\n" + indent() + "\"spv\":\n" + indent() + "{\n"; } printEpilogue(std::ostream & out) const379 void printEpilogue(std::ostream& out) const override { out << indent() + "}\n}\n"; } 380 escapeComment(const std::string & s) const381 std::string escapeComment(const std::string& s) const override { 382 std::string newStr; 383 for (auto c : s) { 384 if (c == '"') { 385 newStr += '\\'; 386 newStr += c; 387 } else { 388 newStr += c; 389 } 390 } 391 return newStr; 392 } 393 fmtConstInt(unsigned val,const std::string & name,const char * fmt,bool isLast) const394 std::string fmtConstInt(unsigned val, const std::string& name, 395 const char* fmt, bool isLast) const override { 396 return indent(3) + '"' + name + "\": " + fmtNum("%d", val) + (isLast ? "\n" : ",\n"); 397 } 398 printMeta(std::ostream & out) const399 void printMeta(std::ostream& out) const override 400 { 401 out << indent(2) + "\"meta\":\n" + indent(2) + "{\n"; 402 printComments(out); 403 TPrinter::printMeta(out); 404 out << indent(2) + "},\n"; 405 } 406 commentBeg() const407 std::string commentBeg() const override { return indent(4) + "[\n"; } commentEnd(bool isLast) const408 std::string commentEnd(bool isLast) const override { return indent(4) + (isLast ? "]" : "],"); } commentBOL() const409 std::string commentBOL() const override { return indent(5) + '"'; } commentEOL(bool isLast) const410 std::string commentEOL(bool isLast) const override { return (isLast ? "\"" : "\","); } 411 printComments(std::ostream & out) const412 void printComments(std::ostream& out) const override 413 { 414 out << indent(3) + "\"Comment\":\n" + indent(3) + "[\n"; 415 TPrinter::printComments(out); 416 out << indent(3) + "],\n"; 417 } 418 printDefs(std::ostream & out) const419 void printDefs(std::ostream& out) const override 420 { 421 out << indent(2) + "\"enum\":\n" + indent(2) + "[\n"; 422 TPrinter::printDefs(out); 423 out << indent(2) + "]\n"; 424 } 425 printAll(std::ostream & out) const426 void printAll(std::ostream& out) const override 427 { 428 printPrologue(out); 429 printMeta(out); 430 printDefs(out); 431 printEpilogue(out); 432 } 433 enumBeg(const std::string & s,enumStyle_t style) const434 std::string enumBeg(const std::string& s, enumStyle_t style) const override { 435 if (style == enumMask) 436 return ""; 437 return indent(3) + "{\n" + 438 indent(4) + "\"Name\": \"" + s + "\",\n" + 439 indent(4) + "\"Type\": " + (style == enumShift ? "\"Bit\"" : "\"Value\"") + ",\n" + 440 indent(4) + "\"Values\":\n" + 441 indent(4) + "{\n"; 442 } 443 enumEnd(const std::string & s,enumStyle_t style,bool isLast) const444 std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override { 445 if (style == enumMask) 446 return ""; 447 return indent(4) + "}\n" + 448 indent(3) + "}" + (isLast ? "" : ",") + "\n"; 449 } 450 enumFmt(const std::string & s,const valpair_t & v,enumStyle_t style,bool isLast) const451 std::string enumFmt(const std::string& s, const valpair_t& v, 452 enumStyle_t style, bool isLast) const override { 453 if (style == enumMask || style == enumNoMask) 454 return ""; 455 return indent(5) + '"' + prependIfDigit(s, v.second) + "\": " + fmtNum("%d", v.first) + 456 (isLast ? "\n" : ",\n"); 457 } 458 }; 459 460 // base for C and C++ 461 class TPrinterCBase : public TPrinter { 462 protected: printPrologue(std::ostream & out) const463 virtual void printPrologue(std::ostream& out) const override { 464 out << "#ifndef spirv_" << headerGuardSuffix() << std::endl 465 << "#define spirv_" << headerGuardSuffix() << std::endl 466 << std::endl; 467 } 468 printMeta(std::ostream & out) const469 void printMeta(std::ostream& out) const override { 470 out << "#define SPV_VERSION 0x" << std::hex << DocVersion << std::dec << "\n"; 471 out << "#define SPV_REVISION " << DocRevision << "\n"; 472 out << "\n"; 473 474 return TPrinter::printMeta(out); 475 } 476 printEpilogue(std::ostream & out) const477 virtual void printEpilogue(std::ostream& out) const override { 478 out << "#endif // #ifndef spirv_" << headerGuardSuffix() << std::endl; 479 } 480 printTypes(std::ostream & out) const481 virtual void printTypes(std::ostream& out) const override { 482 out << "typedef unsigned int " << pre() << "Id;\n\n"; 483 } 484 fmtConstInt(unsigned val,const std::string & name,const char * fmt,bool isLast) const485 virtual std::string fmtConstInt(unsigned val, const std::string& name, 486 const char* fmt, bool isLast) const override 487 { 488 return std::string("static const unsigned int ") + pre() + name + 489 " = " + fmtNum(fmt, val) + (isLast ? ";\n\n" : ";\n"); 490 } 491 pre() const492 virtual std::string pre() const { return ""; } // C name prefix 493 virtual std::string headerGuardSuffix() const = 0; 494 }; 495 496 // C printer 497 class TPrinterC final : public TPrinterCBase { 498 private: commentBeg() const499 std::string commentBeg() const override { return "/*\n"; } commentEnd(bool isLast) const500 std::string commentEnd(bool isLast) const override { return "*/\n"; } commentBOL() const501 std::string commentBOL() const override { return "** "; } 502 enumBeg(const std::string & s,enumStyle_t style) const503 std::string enumBeg(const std::string& s, enumStyle_t style) const override { 504 return std::string("typedef enum ") + pre() + s + styleStr(style) + "_ {\n"; 505 } 506 enumEnd(const std::string & s,enumStyle_t style,bool isLast) const507 std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override { 508 return "} " + pre() + s + styleStr(style) + ";\n\n"; 509 } 510 enumFmt(const std::string & s,const valpair_t & v,enumStyle_t style,bool isLast) const511 std::string enumFmt(const std::string& s, const valpair_t& v, 512 enumStyle_t style, bool isLast) const override { 513 return indent() + pre() + s + v.second + styleStr(style) + " = " + fmtStyleVal(v.first, style) + ",\n"; 514 } 515 maxEnumFmt(const std::string & s,const valpair_t & v,enumStyle_t style) const516 std::string maxEnumFmt(const std::string& s, const valpair_t& v, 517 enumStyle_t style) const override { 518 return enumFmt(s, v, style, true); 519 } 520 pre() const521 std::string pre() const override { return "Spv"; } // C name prefix headerGuardSuffix() const522 std::string headerGuardSuffix() const override { return "H"; } 523 }; 524 525 // C++ printer 526 class TPrinterCPP : public TPrinterCBase { 527 private: printPrologue(std::ostream & out) const528 void printPrologue(std::ostream& out) const override { 529 TPrinterCBase::printPrologue(out); 530 out << "namespace spv {\n\n"; 531 } 532 printEpilogue(std::ostream & out) const533 void printEpilogue(std::ostream& out) const override { 534 const Json::Value& enums = spvRoot["spv"]["enum"]; 535 536 // Create overloaded operator| for mask types 537 out << "// Overload operator| for mask bit combining\n\n"; 538 539 for (auto opClass = enums.begin(); opClass != enums.end(); ++opClass) { 540 const bool isMask = (*opClass)["Type"].asString() == "Bit"; 541 const auto opName = (*opClass)["Name"].asString(); 542 543 if (isMask) { 544 const auto typeName = opName + styleStr(enumMask); 545 546 out << "inline " + typeName + " operator|(" + typeName + " a, " + typeName + " b) { return " + 547 typeName + "(unsigned(a) | unsigned(b)); }\n"; 548 } 549 } 550 551 out << "\n} // end namespace spv\n\n"; 552 TPrinterCBase::printEpilogue(out); 553 } 554 commentBOL() const555 std::string commentBOL() const override { return "// "; } 556 557 enumBeg(const std::string & s,enumStyle_t style) const558 virtual std::string enumBeg(const std::string& s, enumStyle_t style) const override { 559 return std::string("enum ") + s + styleStr(style) + " {\n"; 560 } 561 enumEnd(const std::string & s,enumStyle_t style,bool isLast) const562 std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override { 563 return "};\n\n"; 564 } 565 enumFmt(const std::string & s,const valpair_t & v,enumStyle_t style,bool isLast) const566 virtual std::string enumFmt(const std::string& s, const valpair_t& v, 567 enumStyle_t style, bool isLast) const override { 568 return indent() + s + v.second + styleStr(style) + " = " + fmtStyleVal(v.first, style) + ",\n"; 569 } 570 maxEnumFmt(const std::string & s,const valpair_t & v,enumStyle_t style) const571 virtual std::string maxEnumFmt(const std::string& s, const valpair_t& v, 572 enumStyle_t style) const override { 573 return enumFmt(s, v, style, true); 574 } 575 576 // The C++ and C++11 headers define types with the same name. So they 577 // should use the same header guard. headerGuardSuffix() const578 std::string headerGuardSuffix() const override { return "HPP"; } 579 580 std::string operators; 581 }; 582 583 // C++11 printer (uses enum classes) 584 class TPrinterCPP11 final : public TPrinterCPP { 585 private: enumBeg(const std::string & s,enumStyle_t style) const586 std::string enumBeg(const std::string& s, enumStyle_t style) const override { 587 return std::string("enum class ") + s + styleStr(style) + " : unsigned {\n"; 588 } 589 enumFmt(const std::string & s,const valpair_t & v,enumStyle_t style,bool isLast) const590 std::string enumFmt(const std::string& s, const valpair_t& v, 591 enumStyle_t style, bool isLast) const override { 592 return indent() + prependIfDigit(s, v.second) + " = " + fmtStyleVal(v.first, style) + ",\n"; 593 } 594 maxEnumFmt(const std::string & s,const valpair_t & v,enumStyle_t style) const595 std::string maxEnumFmt(const std::string& s, const valpair_t& v, 596 enumStyle_t style) const override { 597 return enumFmt(s, v, style, true); 598 } 599 headerGuardSuffix() const600 std::string headerGuardSuffix() const override { return "HPP"; } 601 }; 602 603 // LUA printer 604 class TPrinterLua final : public TPrinter { 605 private: printPrologue(std::ostream & out) const606 void printPrologue(std::ostream& out) const override { out << "spv = {\n"; } 607 printEpilogue(std::ostream & out) const608 void printEpilogue(std::ostream& out) const override { out << "}\n"; } 609 commentBOL() const610 std::string commentBOL() const override { return "-- "; } 611 enumBeg(const std::string & s,enumStyle_t style) const612 std::string enumBeg(const std::string& s, enumStyle_t style) const override { 613 return indent() + s + styleStr(style) + " = {\n"; 614 } 615 enumEnd(const std::string & s,enumStyle_t style,bool isLast) const616 std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override { 617 return indent() + "},\n\n"; 618 } 619 enumFmt(const std::string & s,const valpair_t & v,enumStyle_t style,bool isLast) const620 std::string enumFmt(const std::string& s, const valpair_t& v, 621 enumStyle_t style, bool isLast) const override { 622 return indent(2) + prependIfDigit(s, v.second) + " = " + fmtStyleVal(v.first, style) + ",\n"; 623 } 624 fmtConstInt(unsigned val,const std::string & name,const char * fmt,bool isLast) const625 virtual std::string fmtConstInt(unsigned val, const std::string& name, 626 const char* fmt, bool isLast) const override 627 { 628 return indent() + name + " = " + fmtNum(fmt, val) + (isLast ? ",\n\n" : ",\n"); 629 } 630 }; 631 632 // Python printer 633 class TPrinterPython final : public TPrinter { 634 private: printPrologue(std::ostream & out) const635 void printPrologue(std::ostream& out) const override { out << "spv = {\n"; } 636 printEpilogue(std::ostream & out) const637 void printEpilogue(std::ostream& out) const override { out << "}\n"; } 638 commentBOL() const639 std::string commentBOL() const override { return "# "; } 640 enumBeg(const std::string & s,enumStyle_t style) const641 std::string enumBeg(const std::string& s, enumStyle_t style) const override { 642 return indent() + "'" + s + styleStr(style) + "'" + " : {\n"; 643 } 644 enumEnd(const std::string & s,enumStyle_t style,bool isLast) const645 std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override { 646 return indent() + "},\n\n"; 647 } 648 enumFmt(const std::string & s,const valpair_t & v,enumStyle_t style,bool isLast) const649 std::string enumFmt(const std::string& s, const valpair_t& v, 650 enumStyle_t style, bool isLast) const override { 651 return indent(2) + "'" + prependIfDigit(s, v.second) + "'" + " : " + fmtStyleVal(v.first, style) + ",\n"; 652 } 653 fmtConstInt(unsigned val,const std::string & name,const char * fmt,bool isLast) const654 std::string fmtConstInt(unsigned val, const std::string& name, 655 const char* fmt, bool isLast) const override 656 { 657 return indent() + "'" + name + "'" + " : " + fmtNum(fmt, val) + (isLast ? ",\n\n" : ",\n"); 658 } 659 }; 660 661 } // namespace 662 663 namespace spv { PrintAllHeaders()664 void PrintAllHeaders() 665 { 666 // TODO: Once MSVC 2012 is no longer a factor, use brace initializers here 667 std::vector<std::pair<TLanguage, std::string>> langInfo; 668 669 langInfo.push_back(std::make_pair(ELangC, "spirv.h")); 670 langInfo.push_back(std::make_pair(ELangCPP, "spirv.hpp")); 671 langInfo.push_back(std::make_pair(ELangCPP11, "spirv.hpp11")); 672 langInfo.push_back(std::make_pair(ELangJSON, "spirv.json")); 673 langInfo.push_back(std::make_pair(ELangLua, "spirv.lua")); 674 langInfo.push_back(std::make_pair(ELangPython, "spirv.py")); 675 676 for (const auto& lang : langInfo) { 677 std::ofstream out(lang.second, std::ios::out); 678 679 if ((out.rdstate() & std::ifstream::failbit)) { 680 std::cerr << "Unable to open file: " << lang.second << std::endl; 681 } else { 682 PrintHeader(lang.first, out); 683 } 684 } 685 } 686 687 // Print header for given language to given output stream PrintHeader(TLanguage lang,std::ostream & out)688 void PrintHeader(TLanguage lang, std::ostream& out) 689 { 690 typedef std::unique_ptr<TPrinter> TPrinterPtr; 691 TPrinterPtr p; 692 693 switch (lang) { 694 case ELangC: p = TPrinterPtr(new TPrinterC); break; 695 case ELangCPP: p = TPrinterPtr(new TPrinterCPP); break; 696 case ELangCPP11: p = TPrinterPtr(new TPrinterCPP11); break; 697 case ELangJSON: p = TPrinterPtr(new TPrinterJSON); break; 698 case ELangLua: p = TPrinterPtr(new TPrinterLua); break; 699 case ELangPython: p = TPrinterPtr(new TPrinterPython); break; 700 case ELangAll: PrintAllHeaders(); break; 701 default: 702 std::cerr << "Unknown language." << std::endl; 703 return; 704 } 705 706 // Print the data in the requested format 707 if (p) 708 out << *p << std::endl; 709 710 // object is auto-deleted 711 } 712 713 } // namespace spv 714