1b2a28edaSopenharmony_ci// Copyright (c) 2014-2020 The Khronos Group Inc.
2b2a28edaSopenharmony_ci//
3b2a28edaSopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a copy
4b2a28edaSopenharmony_ci// of this software and/or associated documentation files (the "Materials"),
5b2a28edaSopenharmony_ci// to deal in the Materials without restriction, including without limitation
6b2a28edaSopenharmony_ci// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7b2a28edaSopenharmony_ci// and/or sell copies of the Materials, and to permit persons to whom the
8b2a28edaSopenharmony_ci// Materials are furnished to do so, subject to the following conditions:
9b2a28edaSopenharmony_ci//
10b2a28edaSopenharmony_ci// The above copyright notice and this permission notice shall be included in
11b2a28edaSopenharmony_ci// all copies or substantial portions of the Materials.
12b2a28edaSopenharmony_ci//
13b2a28edaSopenharmony_ci// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
14b2a28edaSopenharmony_ci// STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
15b2a28edaSopenharmony_ci// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
16b2a28edaSopenharmony_ci//
17b2a28edaSopenharmony_ci// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18b2a28edaSopenharmony_ci// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19b2a28edaSopenharmony_ci// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20b2a28edaSopenharmony_ci// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21b2a28edaSopenharmony_ci// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22b2a28edaSopenharmony_ci// FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS
23b2a28edaSopenharmony_ci// IN THE MATERIALS.
24b2a28edaSopenharmony_ci
25b2a28edaSopenharmony_ci//
26b2a28edaSopenharmony_ci// Print headers for SPIR-V in several languages.
27b2a28edaSopenharmony_ci//
28b2a28edaSopenharmony_ci// To change the header information, change the C++-built database in doc.*.
29b2a28edaSopenharmony_ci//
30b2a28edaSopenharmony_ci// Then, use "spriv -h <language>" - e.g, spriv.{h,hpp,lua,py,etc}:
31b2a28edaSopenharmony_ci// replace the auto-generated header, or "spirv -H" to generate all
32b2a28edaSopenharmony_ci// supported language headers to predefined names in the current directory.
33b2a28edaSopenharmony_ci//
34b2a28edaSopenharmony_ci
35b2a28edaSopenharmony_ci#include <string>
36b2a28edaSopenharmony_ci#include <sstream>
37b2a28edaSopenharmony_ci#include <fstream>
38b2a28edaSopenharmony_ci#include <cstring>
39b2a28edaSopenharmony_ci#include <cstdio>
40b2a28edaSopenharmony_ci#include <algorithm>
41b2a28edaSopenharmony_ci#include <memory>
42b2a28edaSopenharmony_ci#include <cctype>
43b2a28edaSopenharmony_ci#include <vector>
44b2a28edaSopenharmony_ci#include <utility>
45b2a28edaSopenharmony_ci#include <set>
46b2a28edaSopenharmony_ci
47b2a28edaSopenharmony_ci#include "jsoncpp/dist/json/json.h"
48b2a28edaSopenharmony_ci
49b2a28edaSopenharmony_ci#include "header.h"
50b2a28edaSopenharmony_ci#include "jsonToSpirv.h"
51b2a28edaSopenharmony_ci
52b2a28edaSopenharmony_ci// snprintf and _snprintf are not quite the same, but close enough
53b2a28edaSopenharmony_ci// for our use.
54b2a28edaSopenharmony_ci#ifdef _MSC_VER
55b2a28edaSopenharmony_ci#pragma warning(disable:4996)
56b2a28edaSopenharmony_ci#define snprintf _snprintf
57b2a28edaSopenharmony_ci#endif
58b2a28edaSopenharmony_ci
59b2a28edaSopenharmony_ci// This file converts SPIR-V definitions to an internal JSON
60b2a28edaSopenharmony_ci// representation, and then generates language specific
61b2a28edaSopenharmony_ci// data from that single internal form.
62b2a28edaSopenharmony_ci
63b2a28edaSopenharmony_ci// Initially, the internal form is created from C++ data,
64b2a28edaSopenharmony_ci// though this can be changed to a JSON master in time.
65b2a28edaSopenharmony_ci
66b2a28edaSopenharmony_cinamespace {
67b2a28edaSopenharmony_ci    class TPrinter {
68b2a28edaSopenharmony_ci    protected:
69b2a28edaSopenharmony_ci        TPrinter();
70b2a28edaSopenharmony_ci
71b2a28edaSopenharmony_ci        static const int         DocMagicNumber = 0x07230203;
72b2a28edaSopenharmony_ci        static const int         DocVersion     = 0x00010600;
73b2a28edaSopenharmony_ci        static const int         DocRevision    = 1;
74b2a28edaSopenharmony_ci        #define DocRevisionString                "1"
75b2a28edaSopenharmony_ci        static const std::string DocCopyright;
76b2a28edaSopenharmony_ci        static const std::string DocComment1;
77b2a28edaSopenharmony_ci        static const std::string DocComment2;
78b2a28edaSopenharmony_ci
79b2a28edaSopenharmony_ci        enum enumStyle_t {
80b2a28edaSopenharmony_ci            enumNoMask,
81b2a28edaSopenharmony_ci            enumCount,
82b2a28edaSopenharmony_ci            enumShift,
83b2a28edaSopenharmony_ci            enumMask,
84b2a28edaSopenharmony_ci            enumHex,
85b2a28edaSopenharmony_ci        };
86b2a28edaSopenharmony_ci
87b2a28edaSopenharmony_ci        static std::string styleStr(enumStyle_t s) {
88b2a28edaSopenharmony_ci            return s == enumShift ? "Shift" :
89b2a28edaSopenharmony_ci                   s == enumMask  ? "Mask"  : "";
90b2a28edaSopenharmony_ci        }
91b2a28edaSopenharmony_ci
92b2a28edaSopenharmony_ci        friend std::ostream& operator<<(std::ostream&, const TPrinter&);
93b2a28edaSopenharmony_ci
94b2a28edaSopenharmony_ci        virtual void printAll(std::ostream&)      const;
95b2a28edaSopenharmony_ci        virtual void printComments(std::ostream&) const;
96b2a28edaSopenharmony_ci        virtual void printPrologue(std::ostream&) const { }
97b2a28edaSopenharmony_ci        virtual void printDefs(std::ostream&)     const;
98b2a28edaSopenharmony_ci        virtual void printEpilogue(std::ostream&) const { }
99b2a28edaSopenharmony_ci        virtual void printMeta(std::ostream&)     const;
100b2a28edaSopenharmony_ci        virtual void printTypes(std::ostream&)    const { }
101b2a28edaSopenharmony_ci        virtual void printHasResultType(std::ostream&)     const { };
102b2a28edaSopenharmony_ci
103b2a28edaSopenharmony_ci        virtual std::string escapeComment(const std::string& s) const;
104b2a28edaSopenharmony_ci
105b2a28edaSopenharmony_ci        // Default printComments() uses these comment strings
106b2a28edaSopenharmony_ci        virtual std::string commentBeg() const            { return ""; }
107b2a28edaSopenharmony_ci        virtual std::string commentEnd(bool isLast) const { return ""; }
108b2a28edaSopenharmony_ci        virtual std::string commentBOL() const            { return ""; }
109b2a28edaSopenharmony_ci        virtual std::string commentEOL(bool isLast) const { return ""; }
110b2a28edaSopenharmony_ci
111b2a28edaSopenharmony_ci        typedef std::pair<unsigned, std::string> valpair_t;
112b2a28edaSopenharmony_ci
113b2a28edaSopenharmony_ci        // for printing enum values
114b2a28edaSopenharmony_ci        virtual std::string enumBeg(const std::string&, enumStyle_t) const { return ""; }
115b2a28edaSopenharmony_ci        virtual std::string enumEnd(const std::string&, enumStyle_t, bool isLast = false) const {
116b2a28edaSopenharmony_ci            return "";
117b2a28edaSopenharmony_ci        }
118b2a28edaSopenharmony_ci        virtual std::string enumFmt(const std::string&, const valpair_t&,
119b2a28edaSopenharmony_ci                                    enumStyle_t, bool isLast = false) const {
120b2a28edaSopenharmony_ci            return "";
121b2a28edaSopenharmony_ci        }
122b2a28edaSopenharmony_ci        virtual std::string maxEnumFmt(const std::string&, const valpair_t&,
123b2a28edaSopenharmony_ci                                       enumStyle_t) const {
124b2a28edaSopenharmony_ci            return "";
125b2a28edaSopenharmony_ci        }
126b2a28edaSopenharmony_ci
127b2a28edaSopenharmony_ci        virtual std::string fmtConstInt(unsigned val, const std::string& name,
128b2a28edaSopenharmony_ci                                        const char* fmt, bool isLast = false) const {
129b2a28edaSopenharmony_ci            return "";
130b2a28edaSopenharmony_ci        }
131b2a28edaSopenharmony_ci
132b2a28edaSopenharmony_ci        std::vector<valpair_t> getSortedVals(const Json::Value&) const;
133b2a28edaSopenharmony_ci
134b2a28edaSopenharmony_ci        virtual std::string indent(int count = 1) const {
135b2a28edaSopenharmony_ci            return std::string(count * 4, ' ');   // default indent level = 4
136b2a28edaSopenharmony_ci        }
137b2a28edaSopenharmony_ci
138b2a28edaSopenharmony_ci        static std::string fmtNum(const char* fmt, unsigned val) {
139b2a28edaSopenharmony_ci            char buff[16]; // ample for 8 hex digits + 0x
140b2a28edaSopenharmony_ci            snprintf(buff, sizeof(buff), fmt, val);
141b2a28edaSopenharmony_ci            buff[sizeof(buff)-1] = '\0';  // MSVC doesn't promise null termination
142b2a28edaSopenharmony_ci            return buff;
143b2a28edaSopenharmony_ci        }
144b2a28edaSopenharmony_ci
145b2a28edaSopenharmony_ci        static std::string fmtStyleVal(unsigned v, enumStyle_t style);
146b2a28edaSopenharmony_ci
147b2a28edaSopenharmony_ci        // If the enum value name would start with a sigit, prepend the enum name.
148b2a28edaSopenharmony_ci        // E.g, "3D" -> "Dim3D".
149b2a28edaSopenharmony_ci        static std::string prependIfDigit(const std::string& ename, const std::string& vname) {
150b2a28edaSopenharmony_ci            return (std::isdigit(vname[0]) ? ename : std::string("")) + vname;
151b2a28edaSopenharmony_ci        }
152b2a28edaSopenharmony_ci
153b2a28edaSopenharmony_ci        void addComment(Json::Value& node, const std::string& str);
154b2a28edaSopenharmony_ci
155b2a28edaSopenharmony_ci        Json::Value spvRoot; // JSON SPIR-V data
156b2a28edaSopenharmony_ci    };
157b2a28edaSopenharmony_ci
158b2a28edaSopenharmony_ci    // Format value as mask or value
159b2a28edaSopenharmony_ci    std::string TPrinter::fmtStyleVal(unsigned v, enumStyle_t style)
160b2a28edaSopenharmony_ci    {
161b2a28edaSopenharmony_ci        switch (style) {
162b2a28edaSopenharmony_ci        case enumMask:
163b2a28edaSopenharmony_ci            return fmtNum("0x%08x", 1<<v);
164b2a28edaSopenharmony_ci        case enumHex:
165b2a28edaSopenharmony_ci            return fmtNum("0x%08x", v);
166b2a28edaSopenharmony_ci        default:
167b2a28edaSopenharmony_ci            return std::to_string(v);
168b2a28edaSopenharmony_ci        }
169b2a28edaSopenharmony_ci    }
170b2a28edaSopenharmony_ci
171b2a28edaSopenharmony_ci    const std::string TPrinter::DocCopyright =
172b2a28edaSopenharmony_ci        "Copyright (c) 2014-2020 The Khronos Group Inc.\n"
173b2a28edaSopenharmony_ci        "\n"
174b2a28edaSopenharmony_ci        "Permission is hereby granted, free of charge, to any person obtaining a copy\n"
175b2a28edaSopenharmony_ci        "of this software and/or associated documentation files (the \"Materials\"),\n"
176b2a28edaSopenharmony_ci        "to deal in the Materials without restriction, including without limitation\n"
177b2a28edaSopenharmony_ci        "the rights to use, copy, modify, merge, publish, distribute, sublicense,\n"
178b2a28edaSopenharmony_ci        "and/or sell copies of the Materials, and to permit persons to whom the\n"
179b2a28edaSopenharmony_ci        "Materials are furnished to do so, subject to the following conditions:\n"
180b2a28edaSopenharmony_ci        "\n"
181b2a28edaSopenharmony_ci        "The above copyright notice and this permission notice shall be included in\n"
182b2a28edaSopenharmony_ci        "all copies or substantial portions of the Materials.\n"
183b2a28edaSopenharmony_ci        "\n"
184b2a28edaSopenharmony_ci        "MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS\n"
185b2a28edaSopenharmony_ci        "STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND\n"
186b2a28edaSopenharmony_ci        "HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ \n"
187b2a28edaSopenharmony_ci        "\n"
188b2a28edaSopenharmony_ci        "THE MATERIALS ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n"
189b2a28edaSopenharmony_ci        "OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n"
190b2a28edaSopenharmony_ci        "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n"
191b2a28edaSopenharmony_ci        "THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n"
192b2a28edaSopenharmony_ci        "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n"
193b2a28edaSopenharmony_ci        "FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS\n"
194b2a28edaSopenharmony_ci        "IN THE MATERIALS.\n";
195b2a28edaSopenharmony_ci
196b2a28edaSopenharmony_ci    const std::string TPrinter::DocComment1 =
197b2a28edaSopenharmony_ci        "This header is automatically generated by the same tool that creates\n"
198b2a28edaSopenharmony_ci        "the Binary Section of the SPIR-V specification.\n";
199b2a28edaSopenharmony_ci
200b2a28edaSopenharmony_ci    const std::string TPrinter::DocComment2 =
201b2a28edaSopenharmony_ci        "Enumeration tokens for SPIR-V, in various styles:\n"
202b2a28edaSopenharmony_ci        "  C, C++, C++11, JSON, Lua, Python, C#, D, Beef\n"
203b2a28edaSopenharmony_ci        "\n"
204b2a28edaSopenharmony_ci        "- C will have tokens with a \"Spv\" prefix, e.g.: SpvSourceLanguageGLSL\n"
205b2a28edaSopenharmony_ci        "- C++ will have tokens in the \"spv\" name space, e.g.: spv::SourceLanguageGLSL\n"
206b2a28edaSopenharmony_ci        "- C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL\n"
207b2a28edaSopenharmony_ci        "- Lua will use tables, e.g.: spv.SourceLanguage.GLSL\n"
208b2a28edaSopenharmony_ci        "- Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL']\n"
209b2a28edaSopenharmony_ci        "- C# will use enum classes in the Specification class located in the \"Spv\" namespace,\n"
210b2a28edaSopenharmony_ci        "    e.g.: Spv.Specification.SourceLanguage.GLSL\n"
211b2a28edaSopenharmony_ci        "- D will have tokens under the \"spv\" module, e.g: spv.SourceLanguage.GLSL\n"
212b2a28edaSopenharmony_ci        "- Beef will use enum classes in the Specification class located in the \"Spv\" namespace,\n"
213b2a28edaSopenharmony_ci        "    e.g.: Spv.Specification.SourceLanguage.GLSL\n"
214b2a28edaSopenharmony_ci        "\n"
215b2a28edaSopenharmony_ci        "Some tokens act like mask values, which can be OR'd together,\n"
216b2a28edaSopenharmony_ci        "while others are mutually exclusive.  The mask-like ones have\n"
217b2a28edaSopenharmony_ci        "\"Mask\" in their name, and a parallel enum that has the shift\n"
218b2a28edaSopenharmony_ci        "amount (1 << x) for each corresponding enumerant.\n";
219b2a28edaSopenharmony_ci
220b2a28edaSopenharmony_ci    // Construct
221b2a28edaSopenharmony_ci    TPrinter::TPrinter()
222b2a28edaSopenharmony_ci    {
223b2a28edaSopenharmony_ci        Json::Value& meta            = spvRoot["spv"]["meta"];
224b2a28edaSopenharmony_ci        Json::Value& enums           = spvRoot["spv"]["enum"];
225b2a28edaSopenharmony_ci
226b2a28edaSopenharmony_ci        meta["MagicNumber"]          = DocMagicNumber;
227b2a28edaSopenharmony_ci        meta["Version"]              = DocVersion;
228b2a28edaSopenharmony_ci        meta["Revision"]             = DocRevision;
229b2a28edaSopenharmony_ci        meta["OpCodeMask"]           = 0xffff;
230b2a28edaSopenharmony_ci        meta["WordCountShift"]       = 16;
231b2a28edaSopenharmony_ci
232b2a28edaSopenharmony_ci        int commentId = 0;
233b2a28edaSopenharmony_ci        addComment(meta["Comment"][commentId++], DocCopyright);
234b2a28edaSopenharmony_ci        addComment(meta["Comment"][commentId++], DocComment1);
235b2a28edaSopenharmony_ci        addComment(meta["Comment"][commentId++], DocComment2);
236b2a28edaSopenharmony_ci
237b2a28edaSopenharmony_ci        for (int e = spv::OperandSource; e < spv::OperandOpcode; ++e) {
238b2a28edaSopenharmony_ci            auto& enumSet =  spv::OperandClassParams[e];
239b2a28edaSopenharmony_ci            const bool        mask     = enumSet.bitmask;
240b2a28edaSopenharmony_ci            const std::string enumName = enumSet.codeName;
241b2a28edaSopenharmony_ci
242b2a28edaSopenharmony_ci            for (auto& enumRow : enumSet) {
243b2a28edaSopenharmony_ci                std::string name = enumRow.name;
244b2a28edaSopenharmony_ci                enums[e - spv::OperandSource]["Values"][name] = enumRow.value;
245b2a28edaSopenharmony_ci            }
246b2a28edaSopenharmony_ci
247b2a28edaSopenharmony_ci            enums[e - spv::OperandSource]["Type"] = mask ? "Bit" : "Value";
248b2a28edaSopenharmony_ci            enums[e - spv::OperandSource]["Name"] = enumName;
249b2a28edaSopenharmony_ci        }
250b2a28edaSopenharmony_ci
251b2a28edaSopenharmony_ci          // Instructions are in their own different table
252b2a28edaSopenharmony_ci        {
253b2a28edaSopenharmony_ci            auto& entry = enums[spv::OperandOpcode - spv::OperandSource];
254b2a28edaSopenharmony_ci            for (auto& enumRow : spv::InstructionDesc) {
255b2a28edaSopenharmony_ci                std::string name = enumRow.name;
256b2a28edaSopenharmony_ci                entry["Values"][name] = enumRow.value;
257b2a28edaSopenharmony_ci            }
258b2a28edaSopenharmony_ci            entry["Type"] = "Value";
259b2a28edaSopenharmony_ci            entry["Name"] = "Op";
260b2a28edaSopenharmony_ci        }
261b2a28edaSopenharmony_ci    }
262b2a28edaSopenharmony_ci
263b2a28edaSopenharmony_ci    // Create comment
264b2a28edaSopenharmony_ci    void TPrinter::addComment(Json::Value& node, const std::string& str)
265b2a28edaSopenharmony_ci    {
266b2a28edaSopenharmony_ci        std::istringstream cstream(str);
267b2a28edaSopenharmony_ci        std::string        cline;
268b2a28edaSopenharmony_ci
269b2a28edaSopenharmony_ci        int line = 0;
270b2a28edaSopenharmony_ci        while (std::getline(cstream, cline))  // fmt each line
271b2a28edaSopenharmony_ci            node[line++] = cline;
272b2a28edaSopenharmony_ci    }
273b2a28edaSopenharmony_ci
274b2a28edaSopenharmony_ci
275b2a28edaSopenharmony_ci    // Return a list of values sorted by enum value.  The std::vector
276b2a28edaSopenharmony_ci    // returned by value is okay in c++11 due to move semantics.
277b2a28edaSopenharmony_ci    std::vector<TPrinter::valpair_t>
278b2a28edaSopenharmony_ci    TPrinter::getSortedVals(const Json::Value& p) const
279b2a28edaSopenharmony_ci    {
280b2a28edaSopenharmony_ci        std::vector<valpair_t> values;
281b2a28edaSopenharmony_ci
282b2a28edaSopenharmony_ci        for (auto e = p.begin(); e != p.end(); ++e)
283b2a28edaSopenharmony_ci            values.push_back(valpair_t(e->asUInt(), e.name()));
284b2a28edaSopenharmony_ci
285b2a28edaSopenharmony_ci        // Use a stable sort because we might have aliases, e.g.
286b2a28edaSopenharmony_ci        // SubgropuBallot (might be in future core) vs. SubgroupBallotKHR.
287b2a28edaSopenharmony_ci        std::stable_sort(values.begin(), values.end());
288b2a28edaSopenharmony_ci
289b2a28edaSopenharmony_ci        return values;
290b2a28edaSopenharmony_ci    }
291b2a28edaSopenharmony_ci
292b2a28edaSopenharmony_ci    // Escape comment characters if needed
293b2a28edaSopenharmony_ci    std::string TPrinter::escapeComment(const std::string& s) const { return s; }
294b2a28edaSopenharmony_ci
295b2a28edaSopenharmony_ci    // Format comments in language specific way
296b2a28edaSopenharmony_ci    void TPrinter::printComments(std::ostream& out) const
297b2a28edaSopenharmony_ci    {
298b2a28edaSopenharmony_ci        const int commentCount = spvRoot["spv"]["meta"]["Comment"].size();
299b2a28edaSopenharmony_ci        int commentNum = 0;
300b2a28edaSopenharmony_ci
301b2a28edaSopenharmony_ci        for (const auto& comment : spvRoot["spv"]["meta"]["Comment"]) {
302b2a28edaSopenharmony_ci            out << commentBeg();
303b2a28edaSopenharmony_ci
304b2a28edaSopenharmony_ci            for (int line = 0; line < int(comment.size()); ++line)
305b2a28edaSopenharmony_ci                out << commentBOL() << escapeComment(comment[line].asString()) <<
306b2a28edaSopenharmony_ci                    commentEOL((line+1) == comment.size()) << std::endl;
307b2a28edaSopenharmony_ci
308b2a28edaSopenharmony_ci            out << commentEnd(++commentNum == commentCount) << std::endl;
309b2a28edaSopenharmony_ci        }
310b2a28edaSopenharmony_ci    }
311b2a28edaSopenharmony_ci
312b2a28edaSopenharmony_ci    // Format header metadata
313b2a28edaSopenharmony_ci    void TPrinter::printMeta(std::ostream& out) const
314b2a28edaSopenharmony_ci    {
315b2a28edaSopenharmony_ci        const Json::Value& meta = spvRoot["spv"]["meta"];
316b2a28edaSopenharmony_ci
317b2a28edaSopenharmony_ci        const auto print = [&](const char* name, const char* fmt, bool isLast) {
318b2a28edaSopenharmony_ci            out << fmtConstInt(meta[name].asUInt(), name, fmt, isLast);
319b2a28edaSopenharmony_ci        };
320b2a28edaSopenharmony_ci
321b2a28edaSopenharmony_ci        print("MagicNumber",    "0x%08lx", false);
322b2a28edaSopenharmony_ci        print("Version",        "0x%08lx", false);
323b2a28edaSopenharmony_ci        print("Revision",       "%d",      false);
324b2a28edaSopenharmony_ci        print("OpCodeMask",     "0x%04x",  false);
325b2a28edaSopenharmony_ci        print("WordCountShift", "%d",      true);
326b2a28edaSopenharmony_ci    }
327b2a28edaSopenharmony_ci
328b2a28edaSopenharmony_ci    // Format value definitions in language specific way
329b2a28edaSopenharmony_ci    void TPrinter::printDefs(std::ostream& out) const
330b2a28edaSopenharmony_ci    {
331b2a28edaSopenharmony_ci        const Json::Value& enums = spvRoot["spv"]["enum"];
332b2a28edaSopenharmony_ci
333b2a28edaSopenharmony_ci        for (auto opClass = enums.begin(); opClass != enums.end(); ++opClass) {
334b2a28edaSopenharmony_ci            const bool isMask   = (*opClass)["Type"].asString() == "Bit";
335b2a28edaSopenharmony_ci            const auto opName   = (*opClass)["Name"].asString();
336b2a28edaSopenharmony_ci            const auto opPrefix = opName == "Op" ? "" : opName;
337b2a28edaSopenharmony_ci
338b2a28edaSopenharmony_ci            for (enumStyle_t style = (isMask ? enumShift : enumCount);
339b2a28edaSopenharmony_ci                 style <= (isMask ? enumMask : enumCount); style = enumStyle_t(int(style)+1)) {
340b2a28edaSopenharmony_ci
341b2a28edaSopenharmony_ci                out << enumBeg(opName, style);
342b2a28edaSopenharmony_ci
343b2a28edaSopenharmony_ci                if (style == enumMask)
344b2a28edaSopenharmony_ci                    out << enumFmt(opPrefix, valpair_t(0, "MaskNone"), enumNoMask);
345b2a28edaSopenharmony_ci
346b2a28edaSopenharmony_ci                const auto sorted = getSortedVals((*opClass)["Values"]);
347b2a28edaSopenharmony_ci
348b2a28edaSopenharmony_ci                std::string maxEnum = maxEnumFmt(opName, valpair_t(0x7FFFFFFF, "Max"), enumHex);
349b2a28edaSopenharmony_ci
350b2a28edaSopenharmony_ci                bool printMax = (style != enumMask && maxEnum.size() > 0);
351b2a28edaSopenharmony_ci
352b2a28edaSopenharmony_ci                for (const auto& v : sorted)
353b2a28edaSopenharmony_ci                    out << enumFmt(opPrefix, v, style, !printMax && v.second == sorted.back().second);
354b2a28edaSopenharmony_ci
355b2a28edaSopenharmony_ci                if (printMax)
356b2a28edaSopenharmony_ci                    out << maxEnum;
357b2a28edaSopenharmony_ci
358b2a28edaSopenharmony_ci                auto nextOpClass = opClass;
359b2a28edaSopenharmony_ci                out << enumEnd(opName, style, ++nextOpClass == enums.end());
360b2a28edaSopenharmony_ci            }
361b2a28edaSopenharmony_ci        }
362b2a28edaSopenharmony_ci    }
363b2a28edaSopenharmony_ci
364b2a28edaSopenharmony_ci    void TPrinter::printAll(std::ostream& out) const
365b2a28edaSopenharmony_ci    {
366b2a28edaSopenharmony_ci        printComments(out);
367b2a28edaSopenharmony_ci        printPrologue(out);
368b2a28edaSopenharmony_ci        printTypes(out);
369b2a28edaSopenharmony_ci        printMeta(out);
370b2a28edaSopenharmony_ci        printDefs(out);
371b2a28edaSopenharmony_ci        printHasResultType(out);
372b2a28edaSopenharmony_ci        printEpilogue(out);
373b2a28edaSopenharmony_ci    }
374b2a28edaSopenharmony_ci
375b2a28edaSopenharmony_ci    // Stream entire header to output
376b2a28edaSopenharmony_ci    std::ostream& operator<<(std::ostream& out, const TPrinter &p)
377b2a28edaSopenharmony_ci    {
378b2a28edaSopenharmony_ci        p.printAll(out);
379b2a28edaSopenharmony_ci        return out;
380b2a28edaSopenharmony_ci    }
381b2a28edaSopenharmony_ci
382b2a28edaSopenharmony_ci    // JSON printer.  Rather than use the default printer, we supply our own so
383b2a28edaSopenharmony_ci    // we can control the printing order within various containers.
384b2a28edaSopenharmony_ci    class TPrinterJSON final : public TPrinter {
385b2a28edaSopenharmony_ci    private:
386b2a28edaSopenharmony_ci        void printPrologue(std::ostream& out) const override { out << "{\n" + indent() + "\"spv\":\n" + indent() + "{\n"; }
387b2a28edaSopenharmony_ci        void printEpilogue(std::ostream& out) const override { out << indent() + "}\n}\n"; }
388b2a28edaSopenharmony_ci
389b2a28edaSopenharmony_ci        std::string escapeComment(const std::string& s) const override {
390b2a28edaSopenharmony_ci            std::string newStr;
391b2a28edaSopenharmony_ci            for (auto c : s) {
392b2a28edaSopenharmony_ci                if (c == '"') {
393b2a28edaSopenharmony_ci                    newStr += '\\';
394b2a28edaSopenharmony_ci                    newStr += c;
395b2a28edaSopenharmony_ci                } else {
396b2a28edaSopenharmony_ci                    newStr += c;
397b2a28edaSopenharmony_ci                }
398b2a28edaSopenharmony_ci            }
399b2a28edaSopenharmony_ci            return newStr;
400b2a28edaSopenharmony_ci        }
401b2a28edaSopenharmony_ci
402b2a28edaSopenharmony_ci        std::string fmtConstInt(unsigned val, const std::string& name,
403b2a28edaSopenharmony_ci                                const char* fmt, bool isLast) const override {
404b2a28edaSopenharmony_ci            return indent(3) + '"' + name + "\": " + fmtNum("%d", val) + (isLast ? "\n" : ",\n");
405b2a28edaSopenharmony_ci        }
406b2a28edaSopenharmony_ci
407b2a28edaSopenharmony_ci        void printMeta(std::ostream& out) const override
408b2a28edaSopenharmony_ci        {
409b2a28edaSopenharmony_ci            out << indent(2) + "\"meta\":\n" + indent(2) + "{\n";
410b2a28edaSopenharmony_ci            printComments(out);
411b2a28edaSopenharmony_ci            TPrinter::printMeta(out);
412b2a28edaSopenharmony_ci            out << indent(2) + "},\n";
413b2a28edaSopenharmony_ci        }
414b2a28edaSopenharmony_ci
415b2a28edaSopenharmony_ci        std::string commentBeg() const override            { return indent(4) + "[\n"; }
416b2a28edaSopenharmony_ci        std::string commentEnd(bool isLast) const override { return indent(4) + (isLast ? "]" : "],"); }
417b2a28edaSopenharmony_ci        std::string commentBOL() const override            { return indent(5) + '"'; }
418b2a28edaSopenharmony_ci        std::string commentEOL(bool isLast) const override { return (isLast ? "\"" : "\","); }
419b2a28edaSopenharmony_ci
420b2a28edaSopenharmony_ci        void printComments(std::ostream& out) const override
421b2a28edaSopenharmony_ci        {
422b2a28edaSopenharmony_ci            out << indent(3) + "\"Comment\":\n" + indent(3) + "[\n";
423b2a28edaSopenharmony_ci            TPrinter::printComments(out);
424b2a28edaSopenharmony_ci            out << indent(3) + "],\n";
425b2a28edaSopenharmony_ci        }
426b2a28edaSopenharmony_ci
427b2a28edaSopenharmony_ci        void printDefs(std::ostream& out) const override
428b2a28edaSopenharmony_ci        {
429b2a28edaSopenharmony_ci            out << indent(2) + "\"enum\":\n" + indent(2) + "[\n";
430b2a28edaSopenharmony_ci            TPrinter::printDefs(out);
431b2a28edaSopenharmony_ci            out << indent(2) + "]\n";
432b2a28edaSopenharmony_ci        }
433b2a28edaSopenharmony_ci
434b2a28edaSopenharmony_ci        void printAll(std::ostream& out) const override
435b2a28edaSopenharmony_ci        {
436b2a28edaSopenharmony_ci            printPrologue(out);
437b2a28edaSopenharmony_ci            printMeta(out);
438b2a28edaSopenharmony_ci            printDefs(out);
439b2a28edaSopenharmony_ci            printEpilogue(out);
440b2a28edaSopenharmony_ci        }
441b2a28edaSopenharmony_ci
442b2a28edaSopenharmony_ci        std::string enumBeg(const std::string& s, enumStyle_t style) const override {
443b2a28edaSopenharmony_ci            if (style == enumMask)
444b2a28edaSopenharmony_ci                return "";
445b2a28edaSopenharmony_ci            return indent(3) + "{\n" +
446b2a28edaSopenharmony_ci                indent(4) + "\"Name\": \"" + s + "\",\n" +
447b2a28edaSopenharmony_ci                indent(4) + "\"Type\": " + (style == enumShift ? "\"Bit\"" : "\"Value\"") + ",\n" +
448b2a28edaSopenharmony_ci                indent(4) + "\"Values\":\n" +
449b2a28edaSopenharmony_ci                indent(4) + "{\n";
450b2a28edaSopenharmony_ci        }
451b2a28edaSopenharmony_ci
452b2a28edaSopenharmony_ci        std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override {
453b2a28edaSopenharmony_ci            if (style == enumMask)
454b2a28edaSopenharmony_ci                return "";
455b2a28edaSopenharmony_ci            return indent(4) + "}\n" +
456b2a28edaSopenharmony_ci                   indent(3) + "}" + (isLast ? "" : ",") + "\n";
457b2a28edaSopenharmony_ci        }
458b2a28edaSopenharmony_ci
459b2a28edaSopenharmony_ci        std::string enumFmt(const std::string& s, const valpair_t& v,
460b2a28edaSopenharmony_ci                            enumStyle_t style, bool isLast) const override {
461b2a28edaSopenharmony_ci            if (style == enumMask || style == enumNoMask)
462b2a28edaSopenharmony_ci                return "";
463b2a28edaSopenharmony_ci            return indent(5) + '"' + prependIfDigit(s, v.second) + "\": " + fmtNum("%d", v.first) +
464b2a28edaSopenharmony_ci                (isLast ? "\n" : ",\n");
465b2a28edaSopenharmony_ci        }
466b2a28edaSopenharmony_ci    };
467b2a28edaSopenharmony_ci
468b2a28edaSopenharmony_ci    // base for C and C++
469b2a28edaSopenharmony_ci    class TPrinterCBase : public TPrinter {
470b2a28edaSopenharmony_ci    protected:
471b2a28edaSopenharmony_ci        virtual void printPrologue(std::ostream& out) const override {
472b2a28edaSopenharmony_ci            out << "#ifndef spirv_" << headerGuardSuffix() << std::endl
473b2a28edaSopenharmony_ci                << "#define spirv_" << headerGuardSuffix() << std::endl
474b2a28edaSopenharmony_ci                << std::endl;
475b2a28edaSopenharmony_ci        }
476b2a28edaSopenharmony_ci
477b2a28edaSopenharmony_ci        void printMeta(std::ostream& out) const override {
478b2a28edaSopenharmony_ci            out << "#define SPV_VERSION 0x" << std::hex << DocVersion << std::dec << "\n";
479b2a28edaSopenharmony_ci            out << "#define SPV_REVISION " << DocRevision << "\n";
480b2a28edaSopenharmony_ci            out << "\n";
481b2a28edaSopenharmony_ci
482b2a28edaSopenharmony_ci            return TPrinter::printMeta(out);
483b2a28edaSopenharmony_ci        }
484b2a28edaSopenharmony_ci
485b2a28edaSopenharmony_ci        virtual void printEpilogue(std::ostream& out) const override {
486b2a28edaSopenharmony_ci            out << "#endif" << std::endl;
487b2a28edaSopenharmony_ci        }
488b2a28edaSopenharmony_ci
489b2a28edaSopenharmony_ci        virtual void printTypes(std::ostream& out) const override {
490b2a28edaSopenharmony_ci            out << "typedef unsigned int " << pre() << "Id;\n\n";
491b2a28edaSopenharmony_ci        }
492b2a28edaSopenharmony_ci
493b2a28edaSopenharmony_ci        virtual std::string fmtConstInt(unsigned val, const std::string& name,
494b2a28edaSopenharmony_ci                                        const char* fmt, bool isLast) const override
495b2a28edaSopenharmony_ci        {
496b2a28edaSopenharmony_ci            return std::string("static const unsigned int ") + pre() + name +
497b2a28edaSopenharmony_ci                " = " + fmtNum(fmt, val) + (isLast ? ";\n\n" : ";\n");
498b2a28edaSopenharmony_ci        }
499b2a28edaSopenharmony_ci
500b2a28edaSopenharmony_ci        virtual std::string pre() const { return ""; } // C name prefix
501b2a28edaSopenharmony_ci        virtual std::string headerGuardSuffix() const = 0;
502b2a28edaSopenharmony_ci
503b2a28edaSopenharmony_ci        virtual std::string fmtEnumUse(const std::string& opPrefix, const std::string& name) const { return pre() + name; }
504b2a28edaSopenharmony_ci
505b2a28edaSopenharmony_ci        virtual void printHasResultType(std::ostream& out) const override
506b2a28edaSopenharmony_ci        {
507b2a28edaSopenharmony_ci            const Json::Value& enums = spvRoot["spv"]["enum"];
508b2a28edaSopenharmony_ci
509b2a28edaSopenharmony_ci            std::set<unsigned> seenValues;
510b2a28edaSopenharmony_ci
511b2a28edaSopenharmony_ci            for (auto opClass = enums.begin(); opClass != enums.end(); ++opClass) {
512b2a28edaSopenharmony_ci                const auto opName   = (*opClass)["Name"].asString();
513b2a28edaSopenharmony_ci                if (opName != "Op") {
514b2a28edaSopenharmony_ci                    continue;
515b2a28edaSopenharmony_ci                }
516b2a28edaSopenharmony_ci
517b2a28edaSopenharmony_ci                out << "#ifdef SPV_ENABLE_UTILITY_CODE" << std::endl;
518b2a28edaSopenharmony_ci                out << "#ifndef __cplusplus" << std::endl;
519b2a28edaSopenharmony_ci                out << "#include <stdbool.h>" << std::endl;
520b2a28edaSopenharmony_ci                out << "#endif" << std::endl;
521b2a28edaSopenharmony_ci                out << "inline void " << pre() << "HasResultAndType(" << pre() << opName << " opcode, bool *hasResult, bool *hasResultType) {" << std::endl;
522b2a28edaSopenharmony_ci                out << "    *hasResult = *hasResultType = false;" << std::endl;
523b2a28edaSopenharmony_ci                out << "    switch (opcode) {" << std::endl;
524b2a28edaSopenharmony_ci                out << "    default: /* unknown opcode */ break;" << std::endl;
525b2a28edaSopenharmony_ci
526b2a28edaSopenharmony_ci                for (auto& inst : spv::InstructionDesc) {
527b2a28edaSopenharmony_ci
528b2a28edaSopenharmony_ci                    // Filter out duplicate enum values, which would break the switch statement.
529b2a28edaSopenharmony_ci                    // These are probably just extension enums promoted to core.
530b2a28edaSopenharmony_ci                    if (seenValues.find(inst.value) != seenValues.end()) {
531b2a28edaSopenharmony_ci                        continue;
532b2a28edaSopenharmony_ci                    }
533b2a28edaSopenharmony_ci                    seenValues.insert(inst.value);
534b2a28edaSopenharmony_ci
535b2a28edaSopenharmony_ci                    std::string name = inst.name;
536b2a28edaSopenharmony_ci                    out << "    case " << fmtEnumUse("Op", name) << ": *hasResult = " << (inst.hasResult() ? "true" : "false") << "; *hasResultType = " << (inst.hasType() ? "true" : "false") << "; break;" << std::endl;
537b2a28edaSopenharmony_ci                }
538b2a28edaSopenharmony_ci
539b2a28edaSopenharmony_ci                out << "    }" << std::endl;
540b2a28edaSopenharmony_ci                out << "}" << std::endl;
541b2a28edaSopenharmony_ci                out << "#endif /* SPV_ENABLE_UTILITY_CODE */" << std::endl << std::endl;
542b2a28edaSopenharmony_ci            }
543b2a28edaSopenharmony_ci        }
544b2a28edaSopenharmony_ci    };
545b2a28edaSopenharmony_ci
546b2a28edaSopenharmony_ci    // C printer
547b2a28edaSopenharmony_ci    class TPrinterC final : public TPrinterCBase {
548b2a28edaSopenharmony_ci    private:
549b2a28edaSopenharmony_ci        std::string commentBeg() const override            { return "/*\n"; }
550b2a28edaSopenharmony_ci        std::string commentEnd(bool isLast) const override { return "*/\n"; }
551b2a28edaSopenharmony_ci        std::string commentBOL() const override            { return "** ";  }
552b2a28edaSopenharmony_ci
553b2a28edaSopenharmony_ci        std::string enumBeg(const std::string& s, enumStyle_t style) const override {
554b2a28edaSopenharmony_ci            return std::string("typedef enum ") + pre() + s + styleStr(style) + "_ {\n";
555b2a28edaSopenharmony_ci        }
556b2a28edaSopenharmony_ci
557b2a28edaSopenharmony_ci        std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override {
558b2a28edaSopenharmony_ci            return "} " + pre() + s + styleStr(style) + ";\n\n";
559b2a28edaSopenharmony_ci        }
560b2a28edaSopenharmony_ci
561b2a28edaSopenharmony_ci        std::string enumFmt(const std::string& s, const valpair_t& v,
562b2a28edaSopenharmony_ci                            enumStyle_t style, bool isLast) const override {
563b2a28edaSopenharmony_ci            return indent() + pre() + s + v.second + styleStr(style) + " = " + fmtStyleVal(v.first, style) + ",\n";
564b2a28edaSopenharmony_ci        }
565b2a28edaSopenharmony_ci
566b2a28edaSopenharmony_ci        std::string maxEnumFmt(const std::string& s, const valpair_t& v,
567b2a28edaSopenharmony_ci                               enumStyle_t style) const override {
568b2a28edaSopenharmony_ci            return enumFmt(s, v, style, true);
569b2a28edaSopenharmony_ci        }
570b2a28edaSopenharmony_ci
571b2a28edaSopenharmony_ci        std::string pre() const override { return "Spv"; } // C name prefix
572b2a28edaSopenharmony_ci        std::string headerGuardSuffix() const override { return "H"; }
573b2a28edaSopenharmony_ci    };
574b2a28edaSopenharmony_ci
575b2a28edaSopenharmony_ci    // C++ printer
576b2a28edaSopenharmony_ci    class TPrinterCPP : public TPrinterCBase {
577b2a28edaSopenharmony_ci    protected:
578b2a28edaSopenharmony_ci        void printMaskOperators(std::ostream& out, const std::string& specifiers) const {
579b2a28edaSopenharmony_ci            const Json::Value& enums = spvRoot["spv"]["enum"];
580b2a28edaSopenharmony_ci
581b2a28edaSopenharmony_ci            out << "// Overload bitwise operators for mask bit combining\n\n";
582b2a28edaSopenharmony_ci
583b2a28edaSopenharmony_ci            for (auto opClass = enums.begin(); opClass != enums.end(); ++opClass) {
584b2a28edaSopenharmony_ci                const bool isMask   = (*opClass)["Type"].asString() == "Bit";
585b2a28edaSopenharmony_ci                const auto opName   = (*opClass)["Name"].asString();
586b2a28edaSopenharmony_ci
587b2a28edaSopenharmony_ci                if (isMask) {
588b2a28edaSopenharmony_ci                    const auto typeName = opName + styleStr(enumMask);
589b2a28edaSopenharmony_ci
590b2a28edaSopenharmony_ci                    // Overload operator|
591b2a28edaSopenharmony_ci                    out << specifiers << " " << typeName << " operator|(" << typeName << " a, " << typeName << " b) { return " <<
592b2a28edaSopenharmony_ci                        typeName << "(unsigned(a) | unsigned(b)); }\n";
593b2a28edaSopenharmony_ci                    // Overload operator&
594b2a28edaSopenharmony_ci                    out << specifiers << " " << typeName << " operator&(" << typeName << " a, " << typeName << " b) { return " <<
595b2a28edaSopenharmony_ci                        typeName << "(unsigned(a) & unsigned(b)); }\n";
596b2a28edaSopenharmony_ci                    // Overload operator^
597b2a28edaSopenharmony_ci                    out << specifiers << " " << typeName << " operator^(" << typeName << " a, " << typeName << " b) { return " <<
598b2a28edaSopenharmony_ci                        typeName << "(unsigned(a) ^ unsigned(b)); }\n";
599b2a28edaSopenharmony_ci                    // Overload operator~
600b2a28edaSopenharmony_ci                    out << specifiers << " " << typeName << " operator~(" << typeName << " a) { return " <<
601b2a28edaSopenharmony_ci                        typeName << "(~unsigned(a)); }\n";
602b2a28edaSopenharmony_ci                }
603b2a28edaSopenharmony_ci            }
604b2a28edaSopenharmony_ci        }
605b2a28edaSopenharmony_ci    private:
606b2a28edaSopenharmony_ci        void printPrologue(std::ostream& out) const override {
607b2a28edaSopenharmony_ci            TPrinterCBase::printPrologue(out);
608b2a28edaSopenharmony_ci            out << "namespace spv {\n\n";
609b2a28edaSopenharmony_ci        }
610b2a28edaSopenharmony_ci
611b2a28edaSopenharmony_ci        void printEpilogue(std::ostream& out) const override {
612b2a28edaSopenharmony_ci            printMaskOperators(out, "inline");
613b2a28edaSopenharmony_ci            out << "\n}  // end namespace spv\n\n";
614b2a28edaSopenharmony_ci            out << "#endif  // #ifndef spirv_" << headerGuardSuffix() << std::endl;
615b2a28edaSopenharmony_ci        }
616b2a28edaSopenharmony_ci
617b2a28edaSopenharmony_ci        std::string commentBOL() const override { return "// "; }
618b2a28edaSopenharmony_ci
619b2a28edaSopenharmony_ci
620b2a28edaSopenharmony_ci        virtual std::string enumBeg(const std::string& s, enumStyle_t style) const override {
621b2a28edaSopenharmony_ci            return std::string("enum ") + s + styleStr(style) + " {\n";
622b2a28edaSopenharmony_ci        }
623b2a28edaSopenharmony_ci
624b2a28edaSopenharmony_ci        std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override {
625b2a28edaSopenharmony_ci            return "};\n\n";
626b2a28edaSopenharmony_ci        }
627b2a28edaSopenharmony_ci
628b2a28edaSopenharmony_ci        virtual std::string enumFmt(const std::string& s, const valpair_t& v,
629b2a28edaSopenharmony_ci                                    enumStyle_t style, bool isLast) const override {
630b2a28edaSopenharmony_ci            return indent() + s + v.second + styleStr(style) + " = " + fmtStyleVal(v.first, style) + ",\n";
631b2a28edaSopenharmony_ci        }
632b2a28edaSopenharmony_ci
633b2a28edaSopenharmony_ci        virtual std::string maxEnumFmt(const std::string& s, const valpair_t& v,
634b2a28edaSopenharmony_ci                                       enumStyle_t style) const override {
635b2a28edaSopenharmony_ci            return enumFmt(s, v, style, true);
636b2a28edaSopenharmony_ci        }
637b2a28edaSopenharmony_ci
638b2a28edaSopenharmony_ci        // The C++ and C++11 headers define types with the same name. So they
639b2a28edaSopenharmony_ci        // should use the same header guard.
640b2a28edaSopenharmony_ci        std::string headerGuardSuffix() const override { return "HPP"; }
641b2a28edaSopenharmony_ci
642b2a28edaSopenharmony_ci        std::string operators;
643b2a28edaSopenharmony_ci    };
644b2a28edaSopenharmony_ci
645b2a28edaSopenharmony_ci    // C++11 printer (uses enum classes)
646b2a28edaSopenharmony_ci    class TPrinterCPP11 final : public TPrinterCPP {
647b2a28edaSopenharmony_ci    private:
648b2a28edaSopenharmony_ci        void printEpilogue(std::ostream& out) const override {
649b2a28edaSopenharmony_ci            printMaskOperators(out, "constexpr");
650b2a28edaSopenharmony_ci            out << "\n}  // end namespace spv\n\n";
651b2a28edaSopenharmony_ci            out << "#endif  // #ifndef spirv_" << headerGuardSuffix() << std::endl;
652b2a28edaSopenharmony_ci        }
653b2a28edaSopenharmony_ci        std::string enumBeg(const std::string& s, enumStyle_t style) const override {
654b2a28edaSopenharmony_ci            return std::string("enum class ") + s + styleStr(style) + " : unsigned {\n";
655b2a28edaSopenharmony_ci        }
656b2a28edaSopenharmony_ci
657b2a28edaSopenharmony_ci        std::string enumFmt(const std::string& s, const valpair_t& v,
658b2a28edaSopenharmony_ci                            enumStyle_t style, bool isLast) const override {
659b2a28edaSopenharmony_ci            return indent() + prependIfDigit(s, v.second) + " = " + fmtStyleVal(v.first, style) + ",\n";
660b2a28edaSopenharmony_ci        }
661b2a28edaSopenharmony_ci
662b2a28edaSopenharmony_ci        std::string maxEnumFmt(const std::string& s, const valpair_t& v,
663b2a28edaSopenharmony_ci                               enumStyle_t style) const override {
664b2a28edaSopenharmony_ci            return enumFmt(s, v, style, true);
665b2a28edaSopenharmony_ci        }
666b2a28edaSopenharmony_ci
667b2a28edaSopenharmony_ci        // Add type prefix for scoped enum
668b2a28edaSopenharmony_ci        virtual std::string fmtEnumUse(const std::string& opPrefix, const std::string& name) const override { return opPrefix + "::" + name; }
669b2a28edaSopenharmony_ci
670b2a28edaSopenharmony_ci        std::string headerGuardSuffix() const override { return "HPP"; }
671b2a28edaSopenharmony_ci    };
672b2a28edaSopenharmony_ci
673b2a28edaSopenharmony_ci    // LUA printer
674b2a28edaSopenharmony_ci    class TPrinterLua final : public TPrinter {
675b2a28edaSopenharmony_ci    private:
676b2a28edaSopenharmony_ci        void printPrologue(std::ostream& out) const override { out << "spv = {\n"; }
677b2a28edaSopenharmony_ci
678b2a28edaSopenharmony_ci        void printEpilogue(std::ostream& out) const override { out << "}\n"; }
679b2a28edaSopenharmony_ci
680b2a28edaSopenharmony_ci        std::string commentBOL() const override { return "-- "; }
681b2a28edaSopenharmony_ci
682b2a28edaSopenharmony_ci        std::string enumBeg(const std::string& s, enumStyle_t style) const override {
683b2a28edaSopenharmony_ci            return indent() + s + styleStr(style) + " = {\n";
684b2a28edaSopenharmony_ci        }
685b2a28edaSopenharmony_ci
686b2a28edaSopenharmony_ci        std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override {
687b2a28edaSopenharmony_ci            return indent() + "},\n\n";
688b2a28edaSopenharmony_ci        }
689b2a28edaSopenharmony_ci
690b2a28edaSopenharmony_ci        std::string enumFmt(const std::string& s, const valpair_t& v,
691b2a28edaSopenharmony_ci                            enumStyle_t style, bool isLast) const override {
692b2a28edaSopenharmony_ci            return indent(2) + prependIfDigit(s, v.second) + " = " + fmtStyleVal(v.first, style) + ",\n";
693b2a28edaSopenharmony_ci        }
694b2a28edaSopenharmony_ci
695b2a28edaSopenharmony_ci        virtual std::string fmtConstInt(unsigned val, const std::string& name,
696b2a28edaSopenharmony_ci                                        const char* fmt, bool isLast) const override
697b2a28edaSopenharmony_ci        {
698b2a28edaSopenharmony_ci            return indent() + name + " = " + fmtNum(fmt, val) + (isLast ? ",\n\n" : ",\n");
699b2a28edaSopenharmony_ci        }
700b2a28edaSopenharmony_ci    };
701b2a28edaSopenharmony_ci
702b2a28edaSopenharmony_ci    // Python printer
703b2a28edaSopenharmony_ci    class TPrinterPython final : public TPrinter {
704b2a28edaSopenharmony_ci    private:
705b2a28edaSopenharmony_ci        void printPrologue(std::ostream& out) const override { out << "spv = {\n"; }
706b2a28edaSopenharmony_ci
707b2a28edaSopenharmony_ci        void printEpilogue(std::ostream& out) const override { out << "}\n"; }
708b2a28edaSopenharmony_ci
709b2a28edaSopenharmony_ci        std::string commentBOL() const override { return "# "; }
710b2a28edaSopenharmony_ci
711b2a28edaSopenharmony_ci        std::string enumBeg(const std::string& s, enumStyle_t style) const override {
712b2a28edaSopenharmony_ci            return indent() + "'" + s + styleStr(style) + "'" + " : {\n";
713b2a28edaSopenharmony_ci        }
714b2a28edaSopenharmony_ci
715b2a28edaSopenharmony_ci        std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override {
716b2a28edaSopenharmony_ci            return indent() + "},\n\n";
717b2a28edaSopenharmony_ci        }
718b2a28edaSopenharmony_ci
719b2a28edaSopenharmony_ci        std::string enumFmt(const std::string& s, const valpair_t& v,
720b2a28edaSopenharmony_ci                            enumStyle_t style, bool isLast) const override {
721b2a28edaSopenharmony_ci            return indent(2) + "'" + prependIfDigit(s, v.second) + "'" + " : " + fmtStyleVal(v.first, style) + ",\n";
722b2a28edaSopenharmony_ci        }
723b2a28edaSopenharmony_ci
724b2a28edaSopenharmony_ci        std::string fmtConstInt(unsigned val, const std::string& name,
725b2a28edaSopenharmony_ci                                const char* fmt, bool isLast) const override
726b2a28edaSopenharmony_ci        {
727b2a28edaSopenharmony_ci            return indent() + "'" + name + "'" + " : " + fmtNum(fmt, val) + (isLast ? ",\n\n" : ",\n");
728b2a28edaSopenharmony_ci        }
729b2a28edaSopenharmony_ci    };
730b2a28edaSopenharmony_ci
731b2a28edaSopenharmony_ci    // C# printer
732b2a28edaSopenharmony_ci    class TPrinterCSharp final : public TPrinter {
733b2a28edaSopenharmony_ci    private:
734b2a28edaSopenharmony_ci        std::string commentBOL() const override { return "// ";  }
735b2a28edaSopenharmony_ci
736b2a28edaSopenharmony_ci        void printPrologue(std::ostream& out) const override {
737b2a28edaSopenharmony_ci            out << "namespace Spv\n{\n\n";
738b2a28edaSopenharmony_ci            out << indent() << "public static class Specification\n";
739b2a28edaSopenharmony_ci            out << indent() << "{\n";
740b2a28edaSopenharmony_ci        }
741b2a28edaSopenharmony_ci
742b2a28edaSopenharmony_ci        void printEpilogue(std::ostream& out) const override {
743b2a28edaSopenharmony_ci            out << indent() << "}\n";
744b2a28edaSopenharmony_ci            out << "}\n";
745b2a28edaSopenharmony_ci        }
746b2a28edaSopenharmony_ci
747b2a28edaSopenharmony_ci        std::string enumBeg(const std::string& s, enumStyle_t style) const override {
748b2a28edaSopenharmony_ci            return indent(2) + "public enum " + s + styleStr(style) + "\n" + indent(2) + "{\n";
749b2a28edaSopenharmony_ci        }
750b2a28edaSopenharmony_ci
751b2a28edaSopenharmony_ci        std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override {
752b2a28edaSopenharmony_ci            return indent(2) + "}" + + (isLast ? "\n" : "\n\n");
753b2a28edaSopenharmony_ci        }
754b2a28edaSopenharmony_ci
755b2a28edaSopenharmony_ci        std::string enumFmt(const std::string& s, const valpair_t& v,
756b2a28edaSopenharmony_ci                            enumStyle_t style, bool isLast) const override {
757b2a28edaSopenharmony_ci            return indent(3) + prependIfDigit(s, v.second) + " = " + fmtStyleVal(v.first, style) + ",\n";
758b2a28edaSopenharmony_ci        }
759b2a28edaSopenharmony_ci
760b2a28edaSopenharmony_ci        std::string fmtConstInt(unsigned val, const std::string& name,
761b2a28edaSopenharmony_ci                                const char* fmt, bool isLast) const override {
762b2a28edaSopenharmony_ci            return indent(2) + std::string("public const uint ") + name +
763b2a28edaSopenharmony_ci                " = " + fmtNum(fmt, val) + (isLast ? ";\n\n" : ";\n");
764b2a28edaSopenharmony_ci        }
765b2a28edaSopenharmony_ci    };
766b2a28edaSopenharmony_ci
767b2a28edaSopenharmony_ci    // D printer
768b2a28edaSopenharmony_ci    class TPrinterD final : public TPrinter {
769b2a28edaSopenharmony_ci    private:
770b2a28edaSopenharmony_ci        std::string commentBeg() const override            { return "/+\n"; }
771b2a28edaSopenharmony_ci        std::string commentBOL() const override            { return " + ";  }
772b2a28edaSopenharmony_ci        std::string commentEnd(bool isLast) const override { return " +/\n"; }
773b2a28edaSopenharmony_ci
774b2a28edaSopenharmony_ci        void printPrologue(std::ostream& out) const override {
775b2a28edaSopenharmony_ci            out << "module spv;\n\n";
776b2a28edaSopenharmony_ci        }
777b2a28edaSopenharmony_ci
778b2a28edaSopenharmony_ci        void printEpilogue(std::ostream& out) const override {
779b2a28edaSopenharmony_ci        }
780b2a28edaSopenharmony_ci
781b2a28edaSopenharmony_ci        std::string enumBeg(const std::string& s, enumStyle_t style) const override {
782b2a28edaSopenharmony_ci            return "enum " + s + styleStr(style) + " : uint\n{\n";
783b2a28edaSopenharmony_ci        }
784b2a28edaSopenharmony_ci
785b2a28edaSopenharmony_ci        std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override {
786b2a28edaSopenharmony_ci            return std::string("}\n\n");
787b2a28edaSopenharmony_ci        }
788b2a28edaSopenharmony_ci
789b2a28edaSopenharmony_ci        std::string enumFmt(const std::string& s, const valpair_t& v,
790b2a28edaSopenharmony_ci                            enumStyle_t style, bool isLast) const override {
791b2a28edaSopenharmony_ci            return indent() + prependIfDigit("_", v.second) + " = " + fmtStyleVal(v.first, style) + ",\n";
792b2a28edaSopenharmony_ci        }
793b2a28edaSopenharmony_ci
794b2a28edaSopenharmony_ci        std::string fmtConstInt(unsigned val, const std::string& name,
795b2a28edaSopenharmony_ci                                const char* fmt, bool isLast) const override {
796b2a28edaSopenharmony_ci            return std::string("enum uint ") + name +
797b2a28edaSopenharmony_ci                " = " + fmtNum(fmt, val) + (isLast ? ";\n\n" : ";\n");
798b2a28edaSopenharmony_ci        }
799b2a28edaSopenharmony_ci    };
800b2a28edaSopenharmony_ci
801b2a28edaSopenharmony_ci    // Beef printer
802b2a28edaSopenharmony_ci    class TPrinterBeef final : public TPrinter {
803b2a28edaSopenharmony_ci    private:
804b2a28edaSopenharmony_ci        std::string commentBOL() const override { return "// "; }
805b2a28edaSopenharmony_ci
806b2a28edaSopenharmony_ci        void printPrologue(std::ostream& out) const override {
807b2a28edaSopenharmony_ci            out << "namespace Spv\n{\n";
808b2a28edaSopenharmony_ci            out << indent() << "using System;\n\n";
809b2a28edaSopenharmony_ci            out << indent() << "public static class Specification\n";
810b2a28edaSopenharmony_ci            out << indent() << "{\n";
811b2a28edaSopenharmony_ci        }
812b2a28edaSopenharmony_ci
813b2a28edaSopenharmony_ci        void printEpilogue(std::ostream& out) const override {
814b2a28edaSopenharmony_ci            out << indent() << "}\n";
815b2a28edaSopenharmony_ci            out << "}\n";
816b2a28edaSopenharmony_ci        }
817b2a28edaSopenharmony_ci
818b2a28edaSopenharmony_ci        std::string enumBeg(const std::string& s, enumStyle_t style) const override {
819b2a28edaSopenharmony_ci            return indent(2) + "[AllowDuplicates, CRepr] public enum " + s + styleStr(style) + "\n" + indent(2) + "{\n";
820b2a28edaSopenharmony_ci        }
821b2a28edaSopenharmony_ci
822b2a28edaSopenharmony_ci        std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override {
823b2a28edaSopenharmony_ci            return indent(2) + "}" + +(isLast ? "\n" : "\n\n");
824b2a28edaSopenharmony_ci        }
825b2a28edaSopenharmony_ci
826b2a28edaSopenharmony_ci        std::string enumFmt(const std::string& s, const valpair_t& v,
827b2a28edaSopenharmony_ci            enumStyle_t style, bool isLast) const override {
828b2a28edaSopenharmony_ci            return indent(3) + prependIfDigit(s, v.second) + " = " + fmtStyleVal(v.first, style) + ",\n";
829b2a28edaSopenharmony_ci        }
830b2a28edaSopenharmony_ci
831b2a28edaSopenharmony_ci        std::string fmtConstInt(unsigned val, const std::string& name,
832b2a28edaSopenharmony_ci            const char* fmt, bool isLast) const override {
833b2a28edaSopenharmony_ci            return indent(2) + std::string("public const uint32 ") + name +
834b2a28edaSopenharmony_ci                " = " + fmtNum(fmt, val) + (isLast ? ";\n\n" : ";\n");
835b2a28edaSopenharmony_ci        }
836b2a28edaSopenharmony_ci    };
837b2a28edaSopenharmony_ci
838b2a28edaSopenharmony_ci} // namespace
839b2a28edaSopenharmony_ci
840b2a28edaSopenharmony_cinamespace spv {
841b2a28edaSopenharmony_ci    void PrintAllHeaders()
842b2a28edaSopenharmony_ci    {
843b2a28edaSopenharmony_ci        // TODO: Once MSVC 2012 is no longer a factor, use brace initializers here
844b2a28edaSopenharmony_ci        std::vector<std::pair<TLanguage, std::string>> langInfo;
845b2a28edaSopenharmony_ci
846b2a28edaSopenharmony_ci        langInfo.push_back(std::make_pair(ELangC,       "spirv.h"));
847b2a28edaSopenharmony_ci        langInfo.push_back(std::make_pair(ELangCPP,     "spirv.hpp"));
848b2a28edaSopenharmony_ci        langInfo.push_back(std::make_pair(ELangCPP11,   "spirv.hpp11"));
849b2a28edaSopenharmony_ci        langInfo.push_back(std::make_pair(ELangJSON,    "spirv.json"));
850b2a28edaSopenharmony_ci        langInfo.push_back(std::make_pair(ELangLua,     "spirv.lua"));
851b2a28edaSopenharmony_ci        langInfo.push_back(std::make_pair(ELangPython,  "spirv.py"));
852b2a28edaSopenharmony_ci        langInfo.push_back(std::make_pair(ELangCSharp,  "spirv.cs"));
853b2a28edaSopenharmony_ci        langInfo.push_back(std::make_pair(ELangD,       "spv.d"));
854b2a28edaSopenharmony_ci        langInfo.push_back(std::make_pair(ELangBeef,    "spirv.bf"));
855b2a28edaSopenharmony_ci
856b2a28edaSopenharmony_ci        for (const auto& lang : langInfo) {
857b2a28edaSopenharmony_ci            std::ofstream out(lang.second, std::ios::out);
858b2a28edaSopenharmony_ci
859b2a28edaSopenharmony_ci            if ((out.rdstate() & std::ifstream::failbit)) {
860b2a28edaSopenharmony_ci                std::cerr << "Unable to open file: " << lang.second << std::endl;
861b2a28edaSopenharmony_ci            } else {
862b2a28edaSopenharmony_ci                PrintHeader(lang.first, out);
863b2a28edaSopenharmony_ci            }
864b2a28edaSopenharmony_ci        }
865b2a28edaSopenharmony_ci    }
866b2a28edaSopenharmony_ci
867b2a28edaSopenharmony_ci    // Print header for given language to given output stream
868b2a28edaSopenharmony_ci    void PrintHeader(TLanguage lang, std::ostream& out)
869b2a28edaSopenharmony_ci    {
870b2a28edaSopenharmony_ci        typedef std::unique_ptr<TPrinter> TPrinterPtr;
871b2a28edaSopenharmony_ci        TPrinterPtr p;
872b2a28edaSopenharmony_ci
873b2a28edaSopenharmony_ci        switch (lang) {
874b2a28edaSopenharmony_ci            case ELangC:       p = TPrinterPtr(new TPrinterC);       break;
875b2a28edaSopenharmony_ci            case ELangCPP:     p = TPrinterPtr(new TPrinterCPP);     break;
876b2a28edaSopenharmony_ci            case ELangCPP11:   p = TPrinterPtr(new TPrinterCPP11);   break;
877b2a28edaSopenharmony_ci            case ELangJSON:    p = TPrinterPtr(new TPrinterJSON);    break;
878b2a28edaSopenharmony_ci            case ELangLua:     p = TPrinterPtr(new TPrinterLua);     break;
879b2a28edaSopenharmony_ci            case ELangPython:  p = TPrinterPtr(new TPrinterPython);  break;
880b2a28edaSopenharmony_ci            case ELangCSharp:  p = TPrinterPtr(new TPrinterCSharp);  break;
881b2a28edaSopenharmony_ci            case ELangD:       p = TPrinterPtr(new TPrinterD);       break;
882b2a28edaSopenharmony_ci            case ELangBeef:    p = TPrinterPtr(new TPrinterBeef);    break;
883b2a28edaSopenharmony_ci            case ELangAll:     PrintAllHeaders();                    break;
884b2a28edaSopenharmony_ci            default:
885b2a28edaSopenharmony_ci                std::cerr << "Unknown language." << std::endl;
886b2a28edaSopenharmony_ci                return;
887b2a28edaSopenharmony_ci        }
888b2a28edaSopenharmony_ci
889b2a28edaSopenharmony_ci        // Print the data in the requested format
890b2a28edaSopenharmony_ci        if (p)
891b2a28edaSopenharmony_ci            out << *p << std::endl;
892b2a28edaSopenharmony_ci
893b2a28edaSopenharmony_ci        // object is auto-deleted
894b2a28edaSopenharmony_ci    }
895b2a28edaSopenharmony_ci
896b2a28edaSopenharmony_ci} // namespace spv
897