• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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