1//
2// Copyright (C) 2024 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17package vulkan_xml
18
19import (
20	"berberis/cpp_types"
21	"berberis/vulkan_types"
22	"encoding/xml"
23	"errors"
24	"fmt"
25	"regexp"
26	"sort"
27	"strconv"
28	"strings"
29)
30
31// Vulkan XML includes one platform entity which has many sub entities.
32// We need XMLName for root elements, but validity of all other entities
33// is guaranteed because of XML attributes.
34type registry struct {
35	XMLName    xml.Name       `xml:"registry"`
36	Platforms  []platformInfo `xml:"platforms>platform"`
37	Tags       []tagInfo      `xml:"tags>tag"`
38	Types      []typeInfo     `xml:"types>type"`
39	Enums      []enumInfo     `xml:"enums"`
40	Commands   []commandInfo  `xml:"commands>command"`
41	Extensions []struct {
42		Name     string `xml:"name,attr"`
43		ID       int64  `xml:"number,attr"`
44		Requires []struct {
45			EnumFields []enumFieldInfo `xml:"enum"`
46		} `xml:"require"`
47	} `xml:"extensions>extension"`
48	Features []struct {
49		EnumFields []enumFieldInfo `xml:"enum"`
50	} `xml:"feature>require"`
51	Comments string `xml:"comment"`
52}
53
54type platformInfo struct {
55	Name    string `xml:"name,attr"`
56	Comment string `xml:"comment,attr"`
57}
58
59type tagInfo struct {
60	Name    string `xml:"name,attr"`
61	Author  string `xml:"author,attr"`
62	Contact string `xml:"contact,attr"`
63	Comment string `xml:"comment,attr"`
64}
65
66type typeInfo struct {
67	Name          string                 `xml:"name,attr"`
68	Category      string                 `xml:"category,attr"`
69	Requires      string                 `xml:"requires,attr"`
70	Alias         string                 `xml:"alias,attr"`
71	Members       []structuralMemberInfo `xml:"member"`
72	StructExtends string                 `xml:"structextends,attr"`
73	RawXML        string                 `xml:",innerxml"`
74	Comment       string                 `xml:"comment,attr"`
75	Api           string                 `xml:"api,attr"`
76}
77
78type enumInfo struct {
79	Name       string          `xml:"name,attr"`
80	EnumFields []enumFieldInfo `xml:"enum"`
81}
82
83type enumFieldInfo struct {
84	Name    string `xml:"name,attr"`
85	Alias   string `xml:"alias,attr"`
86	Value   string `xml:"value,attr"`
87	BitPos  string `xml:"bitpos,attr"`
88	Dir     string `xml:"dir,attr"`
89	Extends string `xml:"extends,attr"`
90	ExtID   int64  `xml:"extnumber,attr"`
91	Offset  int64  `xml:"offset,attr"`
92}
93
94type commandInfo struct {
95	Name  string `xml:"name,attr"`
96	Alias string `xml:"alias,attr"`
97	Proto struct {
98		Type    string `xml:"type,attr"`
99		RawXML  string `xml:",innerxml"`
100		Comment string `xml:"comment,attr"`
101	} `xml:"proto"`
102	Params []structuralMemberInfo `xml:"param"`
103	RawXML string                 `xml:",innerxml"`
104}
105
106type structuralMemberInfo struct {
107	Name         string `xml:"name,attr"`
108	Type         string `xml:"type,attr"`
109	Value        string `xml:"values,attr"`
110	Length       string `xml:"len,attr"`
111	AltLength    string `xml:"altlen,attr"`
112	Validstructs string `xml:"validstructs,attr"`
113	RawXML       string `xml:",innerxml"`
114	Comment      string `xml:"comment,attr"`
115	Api          string `xml:"api,attr"`
116}
117
118type ExtendedStructInfo interface {
119	ExtendedWith() []cpp_types.Type
120	OptionalStruct() bool
121	OptionalValue() string
122}
123
124func ExtendedStruct(base_struct cpp_types.Type, optional_struct bool, optional_value string) cpp_types.Type {
125	return &extendedStruct{base_struct, []cpp_types.Type{}, optional_struct, optional_value}
126}
127
128type extendedStruct struct {
129	cpp_types.Type
130	extended_with   []cpp_types.Type
131	optional_struct bool
132	optional_value  string
133}
134
135func (extended_struct *extendedStruct) ExtendedWith() []cpp_types.Type {
136	return extended_struct.extended_with
137}
138
139func (extended_struct *extendedStruct) OptionalStruct() bool {
140	return extended_struct.optional_struct
141}
142
143func (extended_struct *extendedStruct) OptionalValue() string {
144	return extended_struct.optional_value
145}
146
147func ExtendedField(name string, typе cpp_types.Type, length, field cpp_types.FieldInfo) cpp_types.FieldInfo {
148	return &extendedField{cpp_types.Field(name, typе), length, field}
149}
150
151type ExtendedFieldInfo interface {
152	Length() cpp_types.FieldInfo
153	NestedField() cpp_types.FieldInfo
154}
155
156type extendedField struct {
157	cpp_types.FieldInfo
158	length       cpp_types.FieldInfo
159	nested_field cpp_types.FieldInfo
160}
161
162func (field_info *extendedField) BaseFieldInfo() cpp_types.FieldInfo {
163	return field_info
164}
165
166func (field_info *extendedField) Length() cpp_types.FieldInfo {
167	return field_info.length
168}
169
170func (field_info *extendedField) NestedField() cpp_types.FieldInfo {
171	return field_info.nested_field
172}
173
174// Certain types come from platform files and vk.xml doesn't declare them.
175// Not even category name is specified, so we have no idea if these are types
176// or includes or anything else.
177var known_types = map[string]string{
178	"_screen_context":                      "screen/screen.h",
179	"_screen_window":                       "screen/screen.h",
180	"_screen_buffer":                       "screen/screen.h",
181	"NvSciSyncAttrList":                    "nvscisync.h",
182	"NvSciSyncObj":                         "nvscisync.h",
183	"NvSciSyncFence":                       "nvscisync.h",
184	"NvSciBufAttrList":                     "nvscibuf.h",
185	"NvSciBufObj":                          "nvscibuf.h",
186	"char":                                 "vk_platform",
187	"Display":                              "X11/Xlib.h",
188	"DWORD":                                "windows.h",
189	"float":                                "vk_platform",
190	"double":                               "vk_platform",
191	"GgpFrameToken":                        "ggp_c/vulkan_types.h",
192	"GgpStreamDescriptor":                  "ggp_c/vulkan_types.h",
193	"HANDLE":                               "windows.h",
194	"HINSTANCE":                            "windows.h",
195	"HMONITOR":                             "windows.h",
196	"HWND":                                 "windows.h",
197	"IDirectFB":                            "directfb.h",
198	"IDirectFBSurface":                     "directfb.h",
199	"int":                                  "",
200	"int8_t":                               "vk_platform",
201	"int16_t":                              "vk_platform",
202	"int32_t":                              "vk_platform",
203	"int64_t":                              "vk_platform",
204	"LPCWSTR":                              "windows.h",
205	"RROutput":                             "X11/extensions/Xrandr.h",
206	"SECURITY_ATTRIBUTES":                  "windows.h",
207	"size_t":                               "vk_platform",
208	"StdVideoDecodeH264Mvc":                "vk_video/vulkan_video_codec_h264std_decode.h",
209	"StdVideoDecodeH264MvcElement":         "vk_video/vulkan_video_codec_h264std_decode.h",
210	"StdVideoDecodeH264MvcElementFlags":    "vk_video/vulkan_video_codec_h264std_decode.h",
211	"StdVideoDecodeH264PictureInfo":        "vk_video/vulkan_video_codec_h264std_decode.h",
212	"StdVideoDecodeH264PictureInfoFlags":   "vk_video/vulkan_video_codec_h264std_decode.h",
213	"StdVideoDecodeH264ReferenceInfo":      "vk_video/vulkan_video_codec_h264std_decode.h",
214	"StdVideoDecodeH264ReferenceInfoFlags": "vk_video/vulkan_video_codec_h264std_decode.h",
215	"StdVideoDecodeH265PictureInfo":        "vk_video/vulkan_video_codec_h265std_decode.h",
216	"StdVideoDecodeH265PictureInfoFlags":   "vk_video/vulkan_video_codec_h265std_decode.h",
217	"StdVideoDecodeH265ReferenceInfo":      "vk_video/vulkan_video_codec_h265std_decode.h",
218	"StdVideoDecodeH265ReferenceInfoFlags": "vk_video/vulkan_video_codec_h265std_decode.h",
219	"StdVideoEncodeH264PictureInfo":        "vk_video/vulkan_video_codec_h264std_encode.h",
220	"StdVideoEncodeH264PictureInfoFlags":   "vk_video/vulkan_video_codec_h264std_encode.h",
221	"StdVideoEncodeH264RefListModEntry":    "vk_video/vulkan_video_codec_h264std_encode.h",
222	"StdVideoEncodeH264RefMemMgmtCtrlOperations":   "vk_video/vulkan_video_codec_h264std_encode.h",
223	"StdVideoEncodeH264RefMgmtFlags":               "vk_video/vulkan_video_codec_h264std_encode.h",
224	"StdVideoEncodeH264RefPicMarkingEntry":         "vk_video/vulkan_video_codec_h264std_encode.h",
225	"StdVideoEncodeH264ReferenceInfo":              "vk_video/vulkan_video_codec_h264std_encode.h",
226	"StdVideoEncodeH264ReferenceListsInfo":         "vk_video/vulkan_video_codec_h264std_encode.h",
227	"StdVideoEncodeH264ReferenceInfoFlags":         "vk_video/vulkan_video_codec_h264std_encode.h",
228	"StdVideoEncodeH264SliceHeader":                "vk_video/vulkan_video_codec_h264std_encode.h",
229	"StdVideoEncodeH264SliceHeaderFlags":           "vk_video/vulkan_video_codec_h264std_encode.h",
230	"StdVideoEncodeH265PictureInfo":                "vk_video/vulkan_video_codec_h265std_encode.h",
231	"StdVideoEncodeH265PictureInfoFlags":           "vk_video/vulkan_video_codec_h265std_encode.h",
232	"StdVideoEncodeH265ReferenceInfo":              "vk_video/vulkan_video_codec_h265std_encode.h",
233	"StdVideoEncodeH265ReferenceListsInfo":         "vk_video/vulkan_video_codec_h265std_encode.h",
234	"StdVideoEncodeH265ReferenceInfoFlags":         "vk_video/vulkan_video_codec_h265std_encode.h",
235	"StdVideoEncodeH265ReferenceModificationFlags": "vk_video/vulkan_video_codec_h265std_encode.h",
236	"StdVideoEncodeH265ReferenceModifications":     "vk_video/vulkan_video_codec_h265std_encode.h",
237	"StdVideoEncodeH265SliceHeader":                "vk_video/vulkan_video_codec_h265std_encode.h",
238	"StdVideoEncodeH265SliceHeaderFlags":           "vk_video/vulkan_video_codec_h265std_encode.h",
239	"StdVideoEncodeH265SliceSegmentHeader":         "vk_video/vulkan_video_codec_h265std_encode.h",
240	"StdVideoEncodeH265SliceSegmentHeaderFlags":    "vk_video/vulkan_video_codec_h265std_encode.h",
241	"StdVideoH264AspectRatioIdc":                   "vk_video/vulkan_video_codec_h264std.h",
242	"StdVideoH264CabacInitIdc":                     "vk_video/vulkan_video_codec_h264std.h",
243	"StdVideoH264ChromaFormatIdc":                  "vk_video/vulkan_video_codec_h264std.h",
244	"StdVideoH264DisableDeblockingFilterIdc":       "vk_video/vulkan_video_codec_h264std.h",
245	"StdVideoH264HrdParameters":                    "vk_video/vulkan_video_codec_h264std.h",
246	"StdVideoH264Level":                            "vk_video/vulkan_video_codec_h264std.h",
247	"StdVideoH264LevelIdc":                         "vk_video/vulkan_video_codec_h264std.h",
248	"StdVideoH264MemMgmtControlOp":                 "vk_video/vulkan_video_codec_h264std.h",
249	"StdVideoH264ModificationOfPicNumsIdc":         "vk_video/vulkan_video_codec_h264std.h",
250	"StdVideoH264PictureParameterSet":              "vk_video/vulkan_video_codec_h264std.h",
251	"StdVideoH264PictureType":                      "vk_video/vulkan_video_codec_h264std.h",
252	"StdVideoH264PocType":                          "vk_video/vulkan_video_codec_h264std.h",
253	"StdVideoH264PpsFlags":                         "vk_video/vulkan_video_codec_h264std.h",
254	"StdVideoH264ProfileIdc":                       "vk_video/vulkan_video_codec_h264std.h",
255	"StdVideoH264ScalingLists":                     "vk_video/vulkan_video_codec_h264std.h",
256	"StdVideoH264SequenceParameterSet":             "vk_video/vulkan_video_codec_h264std.h",
257	"StdVideoH264SequenceParameterSetVui":          "vk_video/vulkan_video_codec_h264std.h",
258	"StdVideoH264SliceType":                        "vk_video/vulkan_video_codec_h264std.h",
259	"StdVideoH264SpsFlags":                         "vk_video/vulkan_video_codec_h264std.h",
260	"StdVideoH264SpsVuiFlags":                      "vk_video/vulkan_video_codec_h264std.h",
261	"StdVideoH264WeightedBiPredIdc":                "vk_video/vulkan_video_codec_h264std.h",
262	"StdVideoH264WeightedBipredIdc":                "vk_video/vulkan_video_codec_h264std.h",
263	"StdVideoH265PictureParameterSet":              "vk_video/vulkan_video_codec_h265std.h",
264	"StdVideoH265DecPicBufMgr":                     "vk_video/vulkan_video_codec_h265std.h",
265	"StdVideoH265HrdFlags":                         "vk_video/vulkan_video_codec_h265std.h",
266	"StdVideoH265HrdParameters":                    "vk_video/vulkan_video_codec_h265std.h",
267	"StdVideoH265Level":                            "vk_video/vulkan_video_codec_h265std.h",
268	"StdVideoH265LevelIdc":                         "vk_video/vulkan_video_codec_h265std.h",
269	"StdVideoH265PictureType":                      "vk_video/vulkan_video_codec_h265std.h",
270	"StdVideoH265PpsFlags":                         "vk_video/vulkan_video_codec_h265std.h",
271	"StdVideoH265PredictorPaletteEntries":          "vk_video/vulkan_video_codec_h265std.h",
272	"StdVideoH265ProfileIdc":                       "vk_video/vulkan_video_codec_h265std.h",
273	"StdVideoH265ScalingLists":                     "vk_video/vulkan_video_codec_h265std.h",
274	"StdVideoH265SequenceParameterSet":             "vk_video/vulkan_video_codec_h265std.h",
275	"StdVideoH265SequenceParameterSetVui":          "vk_video/vulkan_video_codec_h265std.h",
276	"StdVideoH265SliceType":                        "vk_video/vulkan_video_codec_h265std.h",
277	"StdVideoH265SpsFlags":                         "vk_video/vulkan_video_codec_h265std.h",
278	"StdVideoH265SpsVuiFlags":                      "vk_video/vulkan_video_codec_h265std.h",
279	"StdVideoH265SubLayerHrdParameters":            "vk_video/vulkan_video_codec_h265std.h",
280	"StdVideoH265VideoParameterSet":                "vk_video/vulkan_video_codec_h265std.h",
281	"StdVideoH265VpsFlags":                         "vk_video/vulkan_video_codec_h265std.h",
282	"StdVideoAV1Profile":				"vk_video/vulkan_video_codec_av1std.h",
283	"StdVideoAV1Level":				"vk_video/vulkan_video_codec_av1std.h",
284	"StdVideoAV1SequenceHeader":			"vk_video/vulkan_video_codec_av1std.h",
285	"StdVideoDecodeAV1PictureInfo":			"vk_video/vulkan_video_codec_av1std_decode.h",
286	"StdVideoDecodeAV1ReferenceInfo":		"vk_video/vulkan_video_codec_av1std_decode.h",
287	"uint8_t":                                      "vk_platform",
288	"uint16_t":                                     "vk_platform",
289	"uint32_t":                                     "vk_platform",
290	"uint64_t":                                     "vk_platform",
291	"VisualID":                                     "X11/Xlib.h",
292	"void":                                         "vk_platform",
293	"Window":                                       "X11/Xlib.h",
294	"wl_display":                                   "wayland-client.h",
295	"wl_surface":                                   "wayland-client.h",
296	"xcb_connection_t":                             "xcb/xcb.h",
297	"xcb_visualid_t":                               "xcb/xcb.h",
298	"xcb_window_t":                                 "xcb/xcb.h",
299	"zx_handle_t":                                  "zircon/types.h",
300}
301
302// We don't really parse defines since we don't have a full-blown compiler.
303// Instead we rely on the fact that there are very few defines in vk.xml and just verify that they match out assumptions.
304var known_defines = map[string]string{
305	"VK_MAKE_VERSION": "// DEPRECATED: This define is deprecated. VK_MAKE_API_VERSION should be used instead.\n" +
306		"#define <name>VK_MAKE_VERSION</name>(major, minor, patch) \\\n" +
307		"    ((((uint32_t)(major)) &lt;&lt; 22U) | (((uint32_t)(minor)) &lt;&lt; 12U) | ((uint32_t)(patch)))",
308	"VK_VERSION_MAJOR": "// DEPRECATED: This define is deprecated. VK_API_VERSION_MAJOR should be used instead.\n" +
309		"#define <name>VK_VERSION_MAJOR</name>(version) ((uint32_t)(version) &gt;&gt; 22U)",
310	"VK_VERSION_MINOR": "// DEPRECATED: This define is deprecated. VK_API_VERSION_MINOR should be used instead.\n" +
311		"#define <name>VK_VERSION_MINOR</name>(version) (((uint32_t)(version) &gt;&gt; 12U) &amp; 0x3FFU)",
312	"VK_VERSION_PATCH": "// DEPRECATED: This define is deprecated. VK_API_VERSION_PATCH should be used instead.\n" +
313		"#define <name>VK_VERSION_PATCH</name>(version) ((uint32_t)(version) &amp; 0xFFFU)",
314
315	"VK_MAKE_API_VERSION": "#define <name>VK_MAKE_API_VERSION</name>(variant, major, minor, patch) \\\n" +
316		"    ((((uint32_t)(variant)) &lt;&lt; 29U) | (((uint32_t)(major)) &lt;&lt; 22U) | (((uint32_t)(minor)) &lt;&lt; 12U) | ((uint32_t)(patch)))",
317	"VK_API_VERSION_VARIANT": "#define <name>VK_API_VERSION_VARIANT</name>(version) ((uint32_t)(version) &gt;&gt; 29U)",
318	"VK_API_VERSION_MAJOR":   "#define <name>VK_API_VERSION_MAJOR</name>(version) (((uint32_t)(version) &gt;&gt; 22U) &amp; 0x7FU)",
319	"VK_API_VERSION_MINOR":   "#define <name>VK_API_VERSION_MINOR</name>(version) (((uint32_t)(version) &gt;&gt; 12U) &amp; 0x3FFU)",
320	"VK_API_VERSION_PATCH":   "#define <name>VK_API_VERSION_PATCH</name>(version) ((uint32_t)(version) &amp; 0xFFFU)",
321
322	"VKSC_API_VARIANT": "// Vulkan SC variant number\n#define <name>VKSC_API_VARIANT</name> 1",
323	"VK_API_VERSION": "// DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead.\n" +
324		"//#define <name>VK_API_VERSION</name> <type>VK_MAKE_API_VERSION</type>(0, 1, 0, 0) // Patch version should always be set to 0",
325	"VK_API_VERSION_1_0": "// Vulkan 1.0 version number\n" +
326		"#define <name>VK_API_VERSION_1_0</name> <type>VK_MAKE_API_VERSION</type>(0, 1, 0, 0)// Patch version should always be set to 0",
327	"VK_API_VERSION_1_1": "// Vulkan 1.1 version number\n" +
328		"#define <name>VK_API_VERSION_1_1</name> <type>VK_MAKE_API_VERSION</type>(0, 1, 1, 0)// Patch version should always be set to 0",
329	"VK_API_VERSION_1_2": "// Vulkan 1.2 version number\n" +
330		"#define <name>VK_API_VERSION_1_2</name> <type>VK_MAKE_API_VERSION</type>(0, 1, 2, 0)// Patch version should always be set to 0",
331	"VK_API_VERSION_1_3": "// Vulkan 1.3 version number\n" +
332		"#define <name>VK_API_VERSION_1_3</name> <type>VK_MAKE_API_VERSION</type>(0, 1, 3, 0)// Patch version should always be set to 0",
333	"VK_API_VERSION_1_4": "// Vulkan 1.4 version number\n" +
334		"#define <name>VK_API_VERSION_1_4</name> <type>VK_MAKE_API_VERSION</type>(0, 1, 4, 0)// Patch version should always be set to 0",
335	"VKSC_API_VERSION_1_0": "// Vulkan SC 1.0 version number\n#define <name>VKSC_API_VERSION_1_0</name> <type>VK_MAKE_API_VERSION</type>(VKSC_API_VARIANT, 1, 0, 0)// Patch version should always be set to 0",
336	"VK_HEADER_VERSION": "// Version of this file\n" +
337		"#define <name>VK_HEADER_VERSION</name> ",
338	"VK_HEADER_VERSION_COMPLETE": "// Complete version of this file\n" +
339		"#define <name>VK_HEADER_VERSION_COMPLETE</name> <type>VK_MAKE_API_VERSION</type>",
340	"VK_DEFINE_HANDLE": "\n#define <name>VK_DEFINE_HANDLE</name>(object) typedef struct object##_T* object;",
341	"VK_USE_64_BIT_PTR_DEFINES": "\n" +
342		"#ifndef VK_USE_64_BIT_PTR_DEFINES\n" +
343		"    #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) &amp;&amp; !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) || (defined(__riscv) &amp;&amp; __riscv_xlen == 64)\n" +
344		"        #define VK_USE_64_BIT_PTR_DEFINES 1\n" +
345		"    #else\n" +
346		"        #define VK_USE_64_BIT_PTR_DEFINES 0\n" +
347		"    #endif\n" +
348		"#endif",
349	"VK_NULL_HANDLE": "\n" +
350		"#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE\n" +
351		"    #if (VK_USE_64_BIT_PTR_DEFINES==1)\n" +
352		"        #if (defined(__cplusplus) &amp;&amp; (__cplusplus >= 201103L)) || (defined(_MSVC_LANG) &amp;&amp; (_MSVC_LANG >= 201103L))\n" +
353		"            #define VK_NULL_HANDLE nullptr\n" +
354		"        #else\n" +
355		"            #define VK_NULL_HANDLE ((void*)0)\n" +
356		"        #endif\n" +
357		"    #else\n" +
358		"        #define VK_NULL_HANDLE 0ULL\n" +
359		"    #endif\n" +
360		"#endif\n" +
361		"#ifndef VK_NULL_HANDLE\n" +
362		"    #define VK_NULL_HANDLE 0\n" +
363		"#endif",
364}
365
366var vulkan_known_defines = map[string]string{
367	"VK_DEFINE_HANDLE": "\n#define <name>VK_DEFINE_HANDLE</name>(object) typedef struct object##_T* object;",
368	"VK_DEFINE_NON_DISPATCHABLE_HANDLE": "\n" +
369		"#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE\n" +
370		"    #if (VK_USE_64_BIT_PTR_DEFINES==1)\n" +
371		"        #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object;\n" +
372		"    #else\n" +
373		"        #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;\n" +
374		"    #endif\n" +
375		"#endif",
376}
377
378var vulkansc_known_defines = map[string]string{
379	"VK_DEFINE_HANDLE": "\n#define <name>VK_DEFINE_HANDLE</name>(object) typedef struct object##_T* (object);",
380	"VK_DEFINE_NON_DISPATCHABLE_HANDLE": "\n" +
381		"#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE\n" +
382		"    #if (VK_USE_64_BIT_PTR_DEFINES==1)\n" +
383		"        #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *(object);\n" +
384		"    #else\n" +
385		"        #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t (object);\n" +
386		"    #endif\n" +
387		"#endif",
388}
389
390var known_defines_obsoleted = map[string]string{
391	"VK_MAKE_VERSION": "// DEPRECATED: This define is deprecated. VK_MAKE_API_VERSION should be used instead.\n" +
392		"#define <name>VK_MAKE_VERSION</name>(major, minor, patch) \\\n" +
393		"    ((((uint32_t)(major)) &lt;&lt; 22) | (((uint32_t)(minor)) &lt;&lt; 12) | ((uint32_t)(patch)))",
394	"VK_VERSION_MAJOR": "// DEPRECATED: This define is deprecated. VK_API_VERSION_MAJOR should be used instead.\n" +
395		"#define <name>VK_VERSION_MAJOR</name>(version) ((uint32_t)(version) &gt;&gt; 22)",
396	"VK_VERSION_MINOR": "// DEPRECATED: This define is deprecated. VK_API_VERSION_MINOR should be used instead.\n" +
397		"#define <name>VK_VERSION_MINOR</name>(version) (((uint32_t)(version) &gt;&gt; 12) &amp; 0x3FFU)",
398	"VK_VERSION_PATCH": "// DEPRECATED: This define is deprecated. VK_API_VERSION_PATCH should be used instead.\n" +
399		"#define <name>VK_VERSION_PATCH</name>(version) ((uint32_t)(version) &amp; 0xFFFU)",
400	"VK_MAKE_API_VERSION": "#define <name>VK_MAKE_API_VERSION</name>(variant, major, minor, patch) \\\n" +
401		"    ((((uint32_t)(variant)) &lt;&lt; 29) | (((uint32_t)(major)) &lt;&lt; 22) | (((uint32_t)(minor)) &lt;&lt; 12) | ((uint32_t)(patch)))",
402	"VKSC_API_VARIANT":       "// Vulkan SC variant number \n#define <name>VKSC_API_VARIANT</name> 1 // DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead.",
403	"VK_API_VERSION_VARIANT": "#define <name>VK_API_VERSION_VARIANT</name>(version) ((uint32_t)(version) &gt;&gt; 29)",
404	"VK_API_VERSION_MAJOR":   "#define <name>VK_API_VERSION_MAJOR</name>(version) (((uint32_t)(version) &gt;&gt; 22) &amp; 0x7FU)",
405	"VK_API_VERSION_MINOR":   "#define <name>VK_API_VERSION_MINOR</name>(version) (((uint32_t)(version) &gt;&gt; 12) &amp; 0x3FFU)",
406	"VK_API_VERSION_PATCH":   "#define <name>VK_API_VERSION_PATCH</name>(version) ((uint32_t)(version) &amp; 0xFFFU)",
407	"VK_API_VERSION": "// DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead.\n" +
408		"//#define <name>VK_API_VERSION</name> <type>VK_MAKE_VERSION</type>(1, 0, 0) // Patch version should always be set to 0",
409	"VK_API_VERSION_1_0": "// Vulkan 1.0 version number\n" +
410		"#define <name>VK_API_VERSION_1_0</name> <type>VK_MAKE_VERSION</type>(1, 0, 0)// Patch version should always be set to 0",
411	"VK_API_VERSION_1_1": "// Vulkan 1.1 version number\n" +
412		"#define <name>VK_API_VERSION_1_1</name> <type>VK_MAKE_VERSION</type>(1, 1, 0)// Patch version should always be set to 0",
413	"VK_API_VERSION_1_2": "// Vulkan 1.2 version number\n" +
414		"#define <name>VK_API_VERSION_1_2</name> <type>VK_MAKE_VERSION</type>(1, 2, 0)// Patch version should always be set to 0",
415	"VKSC_API_VERSION_1_0": "VK_MAKE_API_VERSION</type>(VKSC_API_VARIANT, 1, 0, 0)// Patch version should always be set to 0",
416	"VK_HEADER_VERSION": "// Version of this file\n" +
417		"#define <name>VK_HEADER_VERSION</name> ",
418	"VK_HEADER_VERSION_COMPLETE": "// Complete version of this file\n" +
419		"#define <name>VK_HEADER_VERSION_COMPLETE</name> <type>VK_MAKE_VERSION</type>(1, 2, VK_HEADER_VERSION)",
420	"VK_USE_64_BIT_PTR_DEFINES": "\n" +
421		"#ifndef VK_USE_64_BIT_PTR_DEFINES\n" +
422		"    #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) &amp;&amp; !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)\n" +
423		"        #define VK_USE_64_BIT_PTR_DEFINES 1\n" +
424		"    #else\n" +
425		"        #define VK_USE_64_BIT_PTR_DEFINES 0\n" +
426		"    #endif\n" +
427		"#endif",
428	"VK_DEFINE_NON_DISPATCHABLE_HANDLE": "\n#if !defined(VK_DEFINE_NON_DISPATCHABLE_HANDLE)\n" +
429		"#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) &amp;&amp; !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)\n" +
430		"        #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object;\n" +
431		"#else\n" +
432		"        #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;\n" +
433		"#endif\n" +
434		"#endif",
435	"VK_NULL_HANDLE":   "\n#define <name>VK_NULL_HANDLE</name> 0",
436	"VK_DEFINE_HANDLE": "\n#define <name>VK_DEFINE_HANDLE</name>(object) typedef struct object##_T* (object);",
437}
438
439func Unmarshal(data []byte) (*registry, error) {
440	var registry registry
441	err := xml.Unmarshal(data, &registry)
442	if err != nil {
443		return nil, err
444	}
445	for i := range registry.Types {
446		typе := &registry.Types[i]
447		if typе.Name == "" {
448			typе.Name, err = elementFromRawXML("name", typе.RawXML)
449			if err != nil {
450				return nil, err
451			}
452		}
453		if typе.Category == "" {
454			if requires, found := known_types[typе.Name]; !found || typе.Requires != requires {
455				return nil, errors.New("Unknown type without category: \"" + typе.Name + "\"")
456			}
457			typе.Category = "vk_platform"
458		}
459		if typе.Alias != "" || (typе.Category != "struct" && typе.Category != "union") {
460			if len(typе.Members) != 0 {
461				return nil, errors.New("Members in non-struct type : \"" + typе.Name + "\"")
462			}
463		} else {
464			for j := range typе.Members {
465				member := &typе.Members[j]
466				if member.Name == "" {
467					member.Name, err = elementFromRawXML("name", member.RawXML)
468					if err != nil {
469						return nil, err
470					}
471				}
472				if member.Type == "" {
473					member.Type, err = elementFromRawXML("type", member.RawXML)
474					if err != nil {
475						return nil, err
476					}
477				}
478				if member.Comment == "" && strings.Contains(member.RawXML, "<comment>") {
479					member.Comment, err = elementFromRawXML("comment", member.RawXML)
480					if err != nil {
481						return nil, err
482					}
483				}
484			}
485		}
486	}
487	for i := range registry.Commands {
488		command := &registry.Commands[i]
489		if command.Name == "" {
490			command.Name, err = elementFromRawXML("name", command.Proto.RawXML)
491			if err != nil {
492				return nil, err
493			}
494		}
495		if command.Alias == "" {
496			if command.Proto.Type == "" {
497				command.Proto.Type, err = elementFromRawXML("type", command.Proto.RawXML)
498				if err != nil {
499					return nil, err
500				}
501			}
502			if command.Proto.Comment == "" && strings.Contains(command.Proto.RawXML, "<comment>") {
503				command.Proto.Type, err = elementFromRawXML("comment", command.Proto.RawXML)
504				if err != nil {
505					return nil, err
506				}
507			}
508			for j := range command.Params {
509				param := &command.Params[j]
510				if param.Name == "" {
511					param.Name, err = elementFromRawXML("name", param.RawXML)
512					if err != nil {
513						return nil, err
514					}
515				}
516				if param.Type == "" {
517					param.Type, err = elementFromRawXML("type", param.RawXML)
518					if err != nil {
519						return nil, err
520					}
521				}
522				if param.Comment == "" && strings.Contains(command.Proto.RawXML, "<comment>") {
523					param.Comment, err = elementFromRawXML("comment", param.RawXML)
524					if err != nil {
525						return nil, err
526					}
527				}
528			}
529		}
530	}
531	return &registry, nil
532}
533
534func VulkanTypesfromXML(registry *registry) (sorted_type_names []string, types map[string]cpp_types.Type, sorted_command_names []string, commands map[string]cpp_types.Type, extensions map[string]int64, err error) {
535	types = vulkan_types.PlatformTypes()
536	// Note that we don't pre-calculate values for enums during initial parsing because vk.xml
537	// [ab]uses "enum" to define non-integer constants and integers defined-as-C-expression, too.
538	// E.g. "VK_LOD_CLAMP_NONE" as "1000.0f" or VK_QUEUE_FAMILY_FOREIGN_EXT as "(~0U-2)".
539	// We return "raw" string value here and only parse them on as-needed basis.
540	enum_values, enum_types, err := parseEnumValues(registry)
541	if err != nil {
542		return nil, nil, nil, nil, nil, err
543	}
544	// It's allowed in C/C++ to refer to not-yet defined type and type may even include pointer
545	// to itself. But other uses of undefined types are forbidden. Mutually directly (non-pointer)
546	// used types are *forbidden* in C/C++.
547	// Thus the graph of type uses is acyclic when pointers are excluded and we should be
548	// able to iteratively resolve all types by retrying failed types, expecting at least one
549	// type to resolve during an iteration.
550	// The first loop parsing resolves all directly (non-pointer) used types.
551	//
552	// Pointed types just became opaque, if undefined, and will be attempted to be resolved with
553	// a dedicated pass.
554	// The second loop (below) replaces opaque types referenced by pointer if they have been
555	// resolved at some point. Some types are supposed to just be opaque types and be only
556	// operated using pointers — but only platform-provided types, not vk.xml-defined types.
557	var xml_types_list []*typeInfo
558	next_xml_types_list := []*typeInfo{}
559	for index := range registry.Types {
560		next_xml_types_list = append(next_xml_types_list, &registry.Types[index])
561	}
562	for len(next_xml_types_list) > 0 {
563		// If next list is the same as previous one then we have some kind of loop and types couldn't be defined.
564		if len(xml_types_list) == len(next_xml_types_list) {
565			return nil, nil, nil, nil, nil, errors.New("Cannot make any progress: type \"" + xml_types_list[0].Name + "\" refers to undefined type: \"" + xml_types_list[0].RawXML + "\"\"")
566		}
567		xml_types_list = next_xml_types_list
568		next_xml_types_list = []*typeInfo{}
569		for _, xml_type := range xml_types_list {
570			if _, ok := types[xml_type.Name]; ok {
571				if xml_type.Category == "vk_platform" {
572					continue
573				}
574				if xml_type.Api == "vulkansc" {
575					continue
576				}
577				return nil, nil, nil, nil, nil, errors.New("Duplicated type \"" + xml_type.Name + "\"")
578			}
579			if xml_type.Alias != "" {
580				if alias_target, ok := types[xml_type.Alias]; ok {
581					types[xml_type.Name] = cpp_types.AliasType(xml_type.Name, alias_target)
582					continue
583				}
584				next_xml_types_list = append(next_xml_types_list, xml_type)
585				continue
586			}
587			var c_type cpp_types.Type
588			switch xml_type.Category {
589			case "basetype":
590				c_type, err = vulkanBaseTypeFromXML(xml_type)
591			case "bitmask":
592				c_type, err = vulkanBitmaskTypeFromXML(xml_type, types)
593			case "define":
594				err := vulkanDefineTypeFromXML(xml_type)
595				if err != nil {
596					return nil, nil, nil, nil, nil, err
597				}
598				continue
599			case "enum":
600				c_type, err = vulkanEnumTypeFromXML(xml_type, enum_values, enum_types)
601			case "funcpointer":
602				c_type, err = vulkanFuncPoiterTypeFromXML(xml_type, types)
603			case "handle":
604				c_type, err = vulkanHandleTypeFromXML(xml_type, types)
605			case "include":
606				continue
607			case "struct":
608				c_type, err = vulkanStructTypeFromXML(xml_type, xml_type.StructExtends != "", types, enum_values)
609			case "union":
610				c_type, err = vulkanUnionTypeFromXML(xml_type, types, enum_values)
611			case "vk_platform":
612				return nil, nil, nil, nil, nil, errors.New("Unknown platform type \"" + xml_type.Name + "\"")
613			default:
614				return nil, nil, nil, nil, nil, errors.New("Unknown type category \"" + xml_type.Category + "\"")
615			}
616			// This type refers the unknown type. But it maybe because it needs some type defined further on in the xml. Defer its parsing to next pass.
617			if err == unknownType {
618				next_xml_types_list = append(next_xml_types_list, xml_type)
619				continue
620			}
621			if err != nil {
622				return nil, nil, nil, nil, nil, err
623			}
624			types[xml_type.Name] = c_type
625		}
626	}
627	// Populate extended_with info. We need to be the separate path since structs may refer other structs which are defined later in the vk.xml file.
628	for _, xml_type := range registry.Types {
629		if xml_type.Category == "struct" && xml_type.StructExtends != "" {
630			for _, name := range strings.Split(xml_type.StructExtends, ",") {
631				var extended_with *[]cpp_types.Type
632				if types[name].Kind(cpp_types.FirstArch) == cpp_types.Alias {
633					extended_with = &types[name].Elem(cpp_types.FirstArch).(*extendedStruct).extended_with
634				} else {
635					extended_with = &types[name].(*extendedStruct).extended_with
636				}
637				*extended_with = append(*extended_with, types[xml_type.Name])
638			}
639		}
640	}
641	// Resolve potentially circular references.
642	for type_name := range types {
643		// Here we rely on the fact that there are no types in Vulkan which are stuctural in one case yet non-structural
644		// in other cases. And also there are differently-structured structural types either.
645		typе := types[type_name]
646		if typе.Kind(cpp_types.FirstArch) == cpp_types.Ptr {
647			typе = typе.Elem(cpp_types.FirstArch)
648		}
649		if typе.Kind(cpp_types.FirstArch) != cpp_types.Func &&
650			typе.Kind(cpp_types.FirstArch) != cpp_types.Struct &&
651			typе.Kind(cpp_types.FirstArch) != cpp_types.Union {
652			continue
653		}
654		for i := uint(0); i < typе.NumField(cpp_types.FirstArch); i++ {
655			field := typе.Field(i, cpp_types.FirstArch)
656			if field.Type().Kind(cpp_types.FirstArch) != cpp_types.Ptr {
657				continue
658			}
659			pointee_type := field.Type().Elem(cpp_types.FirstArch)
660			if pointee_type.Kind(cpp_types.FirstArch) == cpp_types.Opaque {
661				if field_type, ok := types[pointee_type.Name(cpp_types.FirstArch)]; ok && field_type.Kind(cpp_types.FirstArch) != cpp_types.Opaque {
662					field.Type().(cpp_types.ModifyablePtrType).ReplaceElem(field_type)
663				}
664			} else if pointee_type.Kind(cpp_types.FirstArch) == cpp_types.Const &&
665				pointee_type.Elem(cpp_types.FirstArch).Kind(cpp_types.FirstArch) == cpp_types.Opaque {
666				if field_type, ok := types[pointee_type.Elem(cpp_types.FirstArch).Name(cpp_types.FirstArch)]; ok && field_type.Kind(cpp_types.FirstArch) != cpp_types.Opaque {
667					field.Type().(cpp_types.ModifyablePtrType).ReplaceElem(cpp_types.ConstType(field_type))
668				}
669			}
670		}
671	}
672	commands = make(map[string]cpp_types.Type)
673	for index := range registry.Commands {
674		command := registry.Commands[index]
675		// We'll link aliases below, after the final commands are constructed.
676		if command.Alias != "" {
677			continue
678		}
679		if result_type, ok := types[command.Proto.Type]; ok {
680			if space.ReplaceAllString(command.Proto.RawXML, " ") != fmt.Sprintf("<type>%s</type> <name>%s</name>", command.Proto.Type, command.Name) {
681				return nil, nil, nil, nil, nil, errors.New("Unexpected prototype \"" + command.Proto.RawXML + "\"")
682			}
683			fields_info, err := vulkanStructuralTypeMembersFromXML(command.Name, command.Params, types, enum_values)
684			if err != nil {
685				return nil, nil, nil, nil, nil, err
686			}
687			// Arrays decay into pointers when used as parameters of functions - but only one, outer, dimension.
688			// Convert arrays into pointers, leave other types intact.
689			params_info := []cpp_types.FieldInfo{}
690			for _, field_info := range fields_info {
691				if field_info.Type().Kind(cpp_types.FirstArch) == cpp_types.Array {
692					params_info = append(params_info, ExtendedField(
693						field_info.Name(),
694						cpp_types.PointerType(field_info.Type().Elem(cpp_types.FirstArch)),
695						field_info.BaseFieldInfo().(ExtendedFieldInfo).Length(),
696						field_info.BaseFieldInfo().(ExtendedFieldInfo).NestedField()))
697				} else {
698					params_info = append(params_info, field_info)
699				}
700			}
701			commands[command.Name] = cpp_types.FunctionType(result_type, params_info)
702			continue
703		}
704		return nil, nil, nil, nil, nil, errors.New("Unknown return function type \"" + command.Proto.Type + "\"")
705	}
706	// Now link aliases to the final command of the original function.
707	for index := range registry.Commands {
708		command := registry.Commands[index]
709		if command.Alias == "" {
710			continue
711		}
712		commands[command.Name] = commands[command.Alias]
713	}
714	sorted_type_names = []string{}
715	for name := range types {
716		sorted_type_names = append(sorted_type_names, name)
717	}
718	sort.Strings(sorted_type_names)
719	sorted_command_names = []string{}
720	for name := range commands {
721		sorted_command_names = append(sorted_command_names, name)
722	}
723	sort.Strings(sorted_command_names)
724	extensions = make(map[string]int64)
725	for extension_idx := range registry.Extensions {
726		extension := &registry.Extensions[extension_idx]
727		extensions_spec := int64(-1)
728		for requires_idx := range extension.Requires {
729			requires := &extension.Requires[requires_idx]
730			for enum_field_idx := range requires.EnumFields {
731				enum_field := &requires.EnumFields[enum_field_idx]
732				if enum_field.Alias == "" && strings.HasSuffix(enum_field.Name, "_SPEC_VERSION") {
733					spec_version, err := strconv.ParseInt(enum_field.Value, 10, 32)
734					if err != nil {
735						return nil, nil, nil, nil, nil, err
736					}
737					if spec_version == -1 || extensions_spec != -1 {
738						errors.New("Couldn't find extensions SPEC_VERSION")
739					}
740					extensions_spec = spec_version
741				}
742			}
743		}
744		extensions[extension.Name] = extensions_spec
745	}
746	return sorted_type_names, types, sorted_command_names, commands, extensions, nil
747}
748
749func vulkanBaseTypeFromXML(typе *typeInfo) (cpp_types.Type, error) {
750	RawXML := strings.TrimSpace(space.ReplaceAllString(typе.RawXML, " "))
751	if typе.Name == "CAMetalLayer" {
752		if RawXML != "#ifdef __OBJC__ @class CAMetalLayer; #else typedef void <name>CAMetalLayer</name>; #endif" {
753			return nil, errors.New("Unexpected define \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
754		}
755		return cpp_types.OpaqueType("CAMetalLayer"), nil
756	}
757	if typе.Name == "MTLDevice_id" {
758		if RawXML != "#ifdef __OBJC__ @protocol MTLDevice; typedef __unsafe_unretained id&lt;MTLDevice&gt; MTLDevice_id; #else typedef void* <name>MTLDevice_id</name>; #endif" {
759			return nil, errors.New("Unexpected define \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
760		}
761		return cpp_types.PointerType(cpp_types.VoidType), nil
762	}
763	if typе.Name == "MTLCommandQueue_id" {
764		if RawXML != "#ifdef __OBJC__ @protocol MTLCommandQueue; typedef __unsafe_unretained id&lt;MTLCommandQueue&gt; MTLCommandQueue_id; #else typedef void* <name>MTLCommandQueue_id</name>; #endif" {
765			return nil, errors.New("Unexpected define \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
766		}
767		return cpp_types.PointerType(cpp_types.VoidType), nil
768	}
769	if typе.Name == "MTLBuffer_id" {
770		if RawXML != "#ifdef __OBJC__ @protocol MTLBuffer; typedef __unsafe_unretained id&lt;MTLBuffer&gt; MTLBuffer_id; #else typedef void* <name>MTLBuffer_id</name>; #endif" {
771			return nil, errors.New("Unexpected define \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
772		}
773		return cpp_types.PointerType(cpp_types.VoidType), nil
774	}
775	if typе.Name == "MTLTexture_id" {
776		if RawXML != "#ifdef __OBJC__ @protocol MTLTexture; typedef __unsafe_unretained id&lt;MTLTexture&gt; MTLTexture_id; #else typedef void* <name>MTLTexture_id</name>; #endif" {
777			return nil, errors.New("Unexpected define \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
778		}
779		return cpp_types.PointerType(cpp_types.VoidType), nil
780	}
781	if typе.Name == "MTLSharedEvent_id" {
782		if RawXML != "#ifdef __OBJC__ @protocol MTLSharedEvent; typedef __unsafe_unretained id&lt;MTLSharedEvent&gt; MTLSharedEvent_id; #else typedef void* <name>MTLSharedEvent_id</name>; #endif" {
783			return nil, errors.New("Unexpected define \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
784		}
785		return cpp_types.PointerType(cpp_types.VoidType), nil
786	}
787	if typе.Name == "IOSurfaceRef" {
788		if RawXML != "typedef struct __IOSurface* <name>IOSurfaceRef</name>;" {
789			return nil, errors.New("Unexpected define \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
790		}
791		return cpp_types.PointerType(cpp_types.OpaqueType("__IOSurface")), nil
792	}
793	if RawXML == fmt.Sprintf("struct <name>%s</name>;", typе.Name) {
794		return cpp_types.OpaqueType(typе.Name), nil
795	}
796	if RawXML == fmt.Sprintf("typedef <type>uint32_t</type> <name>%s</name>;", typе.Name) {
797		return cpp_types.AliasType(typе.Name, cpp_types.UInt32TType), nil
798	}
799	if RawXML == fmt.Sprintf("typedef <type>uint64_t</type> <name>%s</name>;", typе.Name) {
800		return cpp_types.AliasType(typе.Name, cpp_types.UInt64TType), nil
801	}
802	if RawXML == fmt.Sprintf("typedef <type>void</type>* <name>%s</name>;", typе.Name) {
803		return cpp_types.AliasType(typе.Name, cpp_types.PointerType(cpp_types.VoidType)), nil
804	}
805	return nil, errors.New("Unexpected basetype \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
806}
807
808func vulkanBitmaskTypeFromXML(typе *typeInfo, types map[string]cpp_types.Type) (cpp_types.Type, error) {
809	RawXML := strings.TrimSpace(space.ReplaceAllString(typе.RawXML, " "))
810	if RawXML == fmt.Sprintf("typedef <type>VkFlags</type> <name>%s</name>;", typе.Name) {
811		return cpp_types.AliasType(typе.Name, types["VkFlags"]), nil
812	}
813	if RawXML == fmt.Sprintf("typedef <type>VkFlags64</type> <name>%s</name>;", typе.Name) {
814		return cpp_types.AliasType(typе.Name, types["VkFlags64"]), nil
815	}
816	return nil, errors.New("Unexpected bitmask \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
817}
818
819func vulkanDefineTypeFromXML(typе *typeInfo) error {
820	if typе.Api == "vulkan" {
821		if define, ok := vulkan_known_defines[typе.Name]; ok {
822			if define != typе.RawXML {
823				return errors.New("Unmatched define \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
824			}
825			return nil
826		}
827	} else if typе.Api == "vulkansc" {
828		if define, ok := vulkansc_known_defines[typе.Name]; ok {
829			if define != typе.RawXML {
830				return errors.New("Unmatched define \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
831			}
832			return nil
833		}
834	} else {
835		if define, ok := vulkan_known_defines[typе.Name]; ok {
836			if define == typе.RawXML {
837				return nil
838			}
839		}
840		if define, ok := vulkansc_known_defines[typе.Name]; ok {
841			if define != typе.RawXML {
842				return errors.New("Unmatched define \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
843			}
844			return nil
845		}
846	}
847	if define, ok := known_defines[typе.Name]; ok {
848		// Most defines are stable and since we don't parse them we just ensure they match our expectations.
849		if typе.Name != "VK_HEADER_VERSION" && typе.Name != "VK_HEADER_VERSION_COMPLETE" {
850			if define != typе.RawXML {
851				if obsolete_define, ok := known_defines_obsoleted[typе.Name]; ok {
852					if obsolete_define == typе.RawXML {
853						return nil
854					}
855					return errors.New("Unmatched define \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
856				}
857				return errors.New("Unknown obsolete define \"" + typе.Name + "\"")
858			}
859			return nil
860		}
861		// Note: VK_HEADER_VERSION is updated every time vk.xml is updated thus we couldn't hardcode it.
862		// VK_HEADER_VERSION_COMPLETE is updted when new, incompatible version of Vulkan is released.
863		if !strings.HasPrefix(typе.RawXML, define) {
864			return errors.New("Unmatched define \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
865		}
866		return nil
867	}
868	return errors.New("Unknown define \"" + typе.Name + "\"")
869}
870
871func vulkanEnumTypeFromXML(typе *typeInfo, enum_values map[string]*enumFieldInfo, enum_types map[string][]*enumFieldInfo) (cpp_types.Type, error) {
872	fits_in_int32 := true
873	fits_in_uint32 := true
874	// Duplicate logic from Khronos's generator.py: use int32_t if everything fits into int32_t,
875	// then uint32_t, then int64_t.
876	basetype := cpp_types.Int32TType
877	for _, element := range enum_types[typе.Name] {
878		value, err := enumFieldValue(element, enum_values)
879		if err != nil {
880			return nil, err
881		}
882		if int64(int32(value)) != value {
883			fits_in_int32 = false
884		}
885		if int64(uint32(value)) != value {
886			fits_in_uint32 = false
887		}
888	}
889	if !fits_in_int32 {
890		if fits_in_uint32 {
891			basetype = cpp_types.UInt32TType
892		} else {
893			basetype = cpp_types.Int64TType
894		}
895	}
896	values := []cpp_types.EnumFieldInfo{}
897	for _, element := range enum_types[typе.Name] {
898		value, _ := enumFieldValue(element, enum_values)
899		values = append(values, cpp_types.EnumField(element.Name, basetype, element.Alias, value))
900	}
901	return cpp_types.EnumType(typе.Name, basetype, values), nil
902}
903
904func vulkanFuncPoiterTypeFromXML(typе *typeInfo, types map[string]cpp_types.Type) (cpp_types.Type, error) {
905	definition := strings.TrimSpace(typе.RawXML)
906	if !strings.HasPrefix(definition, "typedef ") ||
907		!strings.HasSuffix(definition, ");") ||
908		strings.Count(definition, " (VKAPI_PTR *<name>") != 1 ||
909		strings.Count(definition, "</name>)(") != 1 {
910		return nil, errors.New("Couldn't determine function type from \"" + definition + "\"")
911	}
912	split := strings.Split(definition[8:len(definition)-2], " (VKAPI_PTR *<name>")
913	var return_type cpp_types.Type
914	return_type_string := split[0]
915	if strings.HasSuffix(return_type_string, "*") {
916		return_typе, ok := types[return_type_string[0:len(return_type_string)-1]]
917		if !ok {
918			return nil, errors.New("Couldn't determine function type \"" + return_type_string + "\"")
919		}
920		return_type = cpp_types.PointerType(return_typе)
921	} else {
922		return_typе, ok := types[return_type_string]
923		if !ok {
924			return nil, errors.New("Couldn't determine function type \"" + return_type_string + "\"")
925		}
926		return_type = return_typе
927	}
928	parameters := strings.Split(split[1], "</name>)(")[1]
929	var parameter_types []cpp_types.FieldInfo
930	if parameters == "void" {
931		return cpp_types.PointerType(cpp_types.FunctionType(return_type, parameter_types)), nil
932	}
933	for _, parameter := range strings.Split(parameters, ",") {
934		parameter = strings.TrimSpace(parameter)
935		parameter_type_len := strings.LastIndex(parameter, " ")
936		parameter_type := strings.TrimSpace(parameter[:parameter_type_len])
937		parameter_name := strings.TrimSpace(parameter[parameter_type_len+1:])
938		if strings.HasPrefix(parameter_type, "<type>") &&
939			strings.HasSuffix(parameter_type, "</type>") {
940			parameter_types = append(
941				parameter_types,
942				ExtendedField(parameter_name, types[parameter_type[6:len(parameter_type)-7]],
943					nil,
944					nil))
945		} else if strings.HasPrefix(parameter_type, "const <type>") &&
946			strings.HasSuffix(parameter_type, "</type>*") {
947			pointee_type_name := parameter_type[12 : len(parameter_type)-8]
948			if pointee_type, ok := types[pointee_type_name]; ok {
949				parameter_types = append(
950					parameter_types,
951					ExtendedField(
952						parameter_name,
953						cpp_types.PointerType(cpp_types.ConstType(pointee_type)),
954						nil,
955						nil))
956			} else {
957				parameter_types = append(
958					parameter_types,
959					ExtendedField(
960						parameter_name,
961						cpp_types.PointerType(cpp_types.ConstType(cpp_types.OpaqueType(pointee_type_name))),
962						nil,
963						nil))
964			}
965		} else if strings.HasPrefix(parameter_type, "<type>") &&
966			strings.HasSuffix(parameter_type, "</type>*") {
967			pointee_type_name := parameter_type[6 : len(parameter_type)-8]
968			if pointee_type, ok := types[pointee_type_name]; ok {
969				parameter_types = append(
970					parameter_types,
971					ExtendedField(
972						parameter_name,
973						cpp_types.PointerType(pointee_type),
974						nil,
975						nil))
976			} else {
977				parameter_types = append(
978					parameter_types,
979					ExtendedField(
980						parameter_name,
981						cpp_types.PointerType(cpp_types.OpaqueType(pointee_type_name)),
982						nil,
983						nil))
984			}
985		} else {
986			return nil, errors.New("Couldn't determine parameter type \"" + parameter_type + "\"")
987		}
988	}
989	return cpp_types.PointerType(cpp_types.FunctionType(return_type, parameter_types)), nil
990}
991
992func vulkanHandleTypeFromXML(typе *typeInfo, types map[string]cpp_types.Type) (cpp_types.Type, error) {
993	if typе.RawXML == fmt.Sprintf("<type>VK_DEFINE_HANDLE</type>(<name>%s</name>)", typе.Name) {
994		return cpp_types.AliasType(typе.Name, cpp_types.PointerType(cpp_types.OpaqueType(fmt.Sprintf("struct %s_T", typе.Name)))), nil
995	} else if typе.RawXML == fmt.Sprintf("<type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>%s</name>)", typе.Name) {
996		return cpp_types.ArchDependentType(
997			cpp_types.AliasType(typе.Name, cpp_types.UInt64TType),
998			cpp_types.AliasType(typе.Name, cpp_types.PointerType(cpp_types.OpaqueType(fmt.Sprintf("struct %s_T", typе.Name)))),
999			cpp_types.AliasType(typе.Name, cpp_types.UInt64TType),
1000			cpp_types.AliasType(typе.Name, cpp_types.PointerType(cpp_types.OpaqueType(fmt.Sprintf("struct %s_T", typе.Name)))),
1001			cpp_types.AliasType(typе.Name, cpp_types.UInt64TType),
1002			cpp_types.AliasType(typе.Name, cpp_types.PointerType(cpp_types.OpaqueType(fmt.Sprintf("struct %s_T", typе.Name))))), nil
1003	}
1004	return nil, errors.New("Unexpected handle \"" + typе.Name + "\": \"" + typе.RawXML + "\"\"")
1005}
1006
1007func vulkanStructTypeFromXML(typе *typeInfo, optional_struct bool, types map[string]cpp_types.Type, enum_values map[string]*enumFieldInfo) (cpp_types.Type, error) {
1008	fields_info, err := vulkanStructuralTypeMembersFromXML(typе.Name, typе.Members, types, enum_values)
1009	if err != nil {
1010		return nil, err
1011	}
1012	optional_enum_value := ""
1013	if optional_struct {
1014		if typе.Members[0].Type != "VkStructureType" || fields_info[0].Name() != "sType" || fields_info[1].Name() != "pNext" {
1015			return nil, errors.New("Struct extension must have first field named VkStructureType sType and second named pNext")
1016		}
1017		optional_enum_value = typе.Members[0].Value
1018	}
1019	return ExtendedStruct(cpp_types.StructType(typе.Name, fields_info), optional_struct, optional_enum_value), nil
1020}
1021
1022func vulkanUnionTypeFromXML(typе *typeInfo, types map[string]cpp_types.Type, enum_values map[string]*enumFieldInfo) (cpp_types.Type, error) {
1023	fields_info, err := vulkanStructuralTypeMembersFromXML(typе.Name, typе.Members, types, enum_values)
1024	if err != nil {
1025		return nil, err
1026	}
1027	return cpp_types.UnionType(typе.Name, fields_info), nil
1028}
1029
1030var space = regexp.MustCompile(`\s+`)
1031
1032func vulkanStructuralTypeMembersFromXML(name string, members []structuralMemberInfo, types map[string]cpp_types.Type, enum_values map[string]*enumFieldInfo) (result []cpp_types.FieldInfo, err error) {
1033	fields_info := []*extendedField{}
1034	field_map := make(map[string]*extendedField)
1035	for _, member := range members {
1036		html := strings.TrimSpace(member.RawXML)
1037		// Note: checks below count only opening tags because XML parser guarantees that closing tags are there and they
1038		// match opening tags.
1039		if member.Comment != "" {
1040			if comments := strings.Count(html, "<comment>"); comments > 1 {
1041				return nil, errors.New("Unexpected member definition in \"" + name + "\": \"" + html + "\"\"")
1042			} else if comments == 1 {
1043				html = strings.Split(html, "<comment>")[0] + strings.Split(html, "</comment>")[1]
1044			}
1045		}
1046		if strings.Count(html, "<type>") != 1 {
1047			return nil, errors.New("Unexpected member definition in \"" + name + "\": \"" + html + "\"\"")
1048		}
1049		text_before_type_name := strings.TrimSpace(strings.Split(html, "<type>")[0])
1050		text_after_type_name := strings.TrimSpace(strings.Split(html, "</type>")[1])
1051		if strings.Count(html, "<name>") > 1 {
1052			return nil, errors.New("Unexpected member definition in \"" + name + "\": \"" + html + "\"\"")
1053		} else if strings.Count(html, "<name>") == 1 {
1054			text_after_type_name = strings.Split(text_after_type_name, "<name>")[0] + strings.Split(text_after_type_name, "</name>")[1]
1055		}
1056		text_after_type_name = strings.TrimSpace(space.ReplaceAllString(text_after_type_name, " "))
1057		member_type, raw_type_known := types[member.Type]
1058		// TODO(b/268638193): handle comma-separated list of allowed functions.
1059		if member.Type == "VkBaseInStructure" || member.Type == "VkBaseOutStructure" {
1060			member_type = types[member.Validstructs]
1061		}
1062		if len(text_after_type_name) > 0 && text_after_type_name[0] == '*' {
1063			if raw_type_known {
1064				if text_before_type_name == "const" || text_before_type_name == "const struct" {
1065					member_type = cpp_types.ConstType(member_type)
1066				} else if text_before_type_name != "" && text_before_type_name != "struct" {
1067					return nil, errors.New("Unexpected prefix in \"" + name + "\": \"" + html + "\"\"")
1068				}
1069			} else {
1070				member_type = cpp_types.OpaqueType(member.Type)
1071				// Note that if type is opaque in C (but not C++!) if has to be prefixed with either "const struct" or  "struct".
1072				// If we only see "const" or nothing then that type is not opaque and is supposed to be declared somewhere below.
1073				// Return unknownType if that happens.
1074				if text_before_type_name == "" || text_before_type_name == "const" {
1075					return nil, unknownType
1076				} else if text_before_type_name == "const struct" {
1077					member_type = cpp_types.ConstType(member_type)
1078				} else if text_before_type_name != "struct" {
1079					return nil, errors.New("Unexpected member definition in \"" + name + "\": \"" + html + "\"\"")
1080				}
1081			}
1082			if text_after_type_name == "*" {
1083				member_type = cpp_types.PointerType(member_type)
1084			} else if text_after_type_name == "**" {
1085				member_type = cpp_types.PointerType(cpp_types.PointerType(member_type))
1086			} else if text_after_type_name == "* const*" || text_after_type_name == "* const *" {
1087				member_type = cpp_types.PointerType(cpp_types.ConstType(cpp_types.PointerType(member_type)))
1088			} else {
1089				return nil, errors.New("Unexpected member definition in \"" + name + "\": \"" + html + "\"\"")
1090			}
1091		} else {
1092			if !raw_type_known {
1093				return nil, unknownType
1094			}
1095			if text_before_type_name == "const" {
1096				member_type = cpp_types.ConstType(member_type)
1097			} else if text_before_type_name != "" {
1098				return nil, errors.New("Unexpected member definition in \"" + name + "\": \"" + html + "\"\"")
1099			}
1100			// Bitfields are not actually supposed to be used in vk.xml — and it even has comment which says exactly that!
1101			// Unfortunately they are already there and couldn't be removed (backward compatibility!).
1102			// Replace "uint32_t :8" with "uint8_t" and "uint32_t :24" with "uint8_t[3]".
1103			// This is hack but provides proper layout.
1104			if text_after_type_name == ":8" {
1105				if member.Type != "uint32_t" && member.Type != "VkGeometryInstanceFlagsKHR" {
1106					return nil, errors.New("Unsupported bitfield type name \"" + name + "\": \"" + html + "\"\"")
1107				}
1108				member_type = cpp_types.UInt8TType
1109			} else if text_after_type_name == ":24" {
1110				if member.Type != "uint32_t" {
1111					return nil, errors.New("Unsupported bitfield type name \"" + name + "\": \"" + html + "\"\"")
1112				}
1113				member_type = cpp_types.ArrayType(cpp_types.UInt8TType, 3)
1114			} else {
1115				indexes := []uint{}
1116				for strings.HasSuffix(text_after_type_name, "]") {
1117					array_size_text := text_after_type_name[strings.LastIndex(text_after_type_name, "[")+1 : len(text_after_type_name)-1]
1118					text_after_type_name = text_after_type_name[0 : len(text_after_type_name)-len(array_size_text)-2]
1119					if strings.HasPrefix(array_size_text, "<enum>") {
1120						if !strings.HasSuffix(array_size_text, "</enum>") {
1121							return nil, errors.New("Unsupported array index \"" + array_size_text + "\"\"")
1122						}
1123						array_size_text = enum_values[array_size_text[6:len(array_size_text)-7]].Value
1124					}
1125					array_size, err := strconv.ParseInt(array_size_text, 10, 32)
1126					if err != nil {
1127						return nil, err
1128					}
1129					indexes = append(indexes, uint(array_size))
1130				}
1131				for i := len(indexes) - 1; i >= 0; i-- {
1132					member_type = cpp_types.ArrayType(member_type, indexes[i])
1133				}
1134				if text_after_type_name != "" {
1135					return nil, errors.New("Unexpected member definition in \"" + name + "\": \"" + html + "\"\"")
1136				}
1137			}
1138		}
1139		new_field := extendedField{cpp_types.Field(member.Name, member_type), nil, nil}
1140		if member.Api != "vulkansc" {
1141			fields_info = append(fields_info, &new_field)
1142			field_map[member.Name] = &new_field
1143		}
1144	}
1145	for _, member := range members {
1146		// This strange notion is used in VkAccelerationStructureBuildGeometryInfoKHR structure where only one of two fields can be non-NULL:
1147		//   <member len="geometryCount,1" optional="true,false">
1148		// We treat it as <member len="geometryCount" optional="true"> here.
1149		if strings.HasSuffix(member.Length, ",1") {
1150			if length, ok := field_map[member.Length[0:len(member.Length)-2]]; ok {
1151				field_map[member.Name].length = length
1152			} else {
1153				return nil, errors.New("Unexpected len field in \"" + member.Name + "\"")
1154			}
1155			// Some corner cases have len like “pAllocateInfo->descriptorSetCount”.
1156			// Currently that only have one level, structures are always input to function,
1157			// and we don't need to convert these.
1158			//
1159			// We need to detect case where that wouldn't be true in the future.
1160			// Only then would we know how to handle these.
1161			//
1162			// We parse these and pass the information to calling module because it's
1163			// not easy to see here whether types are compatible on all platforms here
1164			// or not (and there are more than a couple of such types).
1165		} else if strings.Contains(member.Length, "->") {
1166			split_length := strings.Split(member.Length, "->")
1167			if len(split_length) > 2 {
1168				return nil, errors.New("Unexpected len field in \"" + member.Name + "\"")
1169			}
1170			length, ok := field_map[split_length[0]]
1171			if !ok {
1172				return nil, errors.New("Unexpected len field in \"" + member.Name + "\"")
1173			}
1174			field_map[member.Name].length = length
1175			// Note: we are dealing with pointer to const data structure here.
1176			// That's why we dereference twice.
1177			length_type := length.Type()
1178			if length_type.Kind(cpp_types.FirstArch) != cpp_types.Ptr {
1179				return nil, errors.New("Unexpected len field in \"" + member.Name + "\"")
1180			}
1181			length_type = length_type.Elem(cpp_types.FirstArch)
1182			if length_type.Kind(cpp_types.FirstArch) == cpp_types.Const {
1183				length_type = length_type.Elem(cpp_types.FirstArch)
1184			}
1185			if length_type.Kind(cpp_types.FirstArch) != cpp_types.Struct &&
1186				length_type.Kind(cpp_types.FirstArch) != cpp_types.Union {
1187				return nil, errors.New("Unexpected len field in \"" + member.Name + "\"")
1188			}
1189			for i := uint(0); i < length_type.NumField(cpp_types.FirstArch); i++ {
1190				if length_type.Field(i, cpp_types.FirstArch).Name() == split_length[1] {
1191					field_map[member.Name].nested_field = length_type.Field(i, cpp_types.FirstArch)
1192				}
1193			}
1194			if field_map[member.Name].nested_field == nil {
1195				return nil, errors.New("Unexpected field referred by len in \"" + member.Name + "\"")
1196			}
1197			// If len is too complicated it may be represented as LaTeX expression (e.g.
1198			// latexmath:[\lceil{\mathit{rasterizationSamples} \over 32}\rceil] for pSampleMask)
1199			// In these cases altlength represents for C, but it may be quite hard to parse that
1200			// too.
1201			// Thankfully for now all such complex fields pass arrays of uint{8,16,32}_t which
1202			// we never translate. Note: we currently don't translate uint64_t even if these
1203			// are not 100% compatible on all platforms. The only direction where that may
1204			// matter would be x86 (32bit) to AArch32 translation (which we don't support),
1205			// but arrays of uint{8,16,32}_t are 100% compatible on all platforums.
1206			//
1207			// Verify that it's so and ignore "len" in that case.
1208		} else if member.AltLength != "" {
1209			typе := field_map[member.Name].Type()
1210			if typе.Kind(cpp_types.FirstArch) != cpp_types.Ptr {
1211				return nil, errors.New("Unexpected altlen field in \"" + member.Name + "\"")
1212			}
1213			element_type := typе.Elem(cpp_types.FirstArch)
1214			if element_type.Kind(cpp_types.FirstArch) == cpp_types.Const {
1215				element_type = element_type.Elem(cpp_types.FirstArch)
1216			}
1217			if element_type.Kind(cpp_types.FirstArch) == cpp_types.Alias {
1218				element_type = element_type.Elem(cpp_types.FirstArch)
1219			}
1220			if element_type.Kind(cpp_types.FirstArch) != cpp_types.UInt8T &&
1221				element_type.Kind(cpp_types.FirstArch) != cpp_types.UInt16T &&
1222				element_type.Kind(cpp_types.FirstArch) != cpp_types.UInt32T {
1223				return nil, errors.New("Unexpected altlen field in \"" + member.Name + "\"")
1224			}
1225			// Weird case with constant 1 length. This is currently only used by GetDeviceSubpassShadingMaxWorkgroupSize,
1226			// for a VkExtent2D, which should not require translation.
1227		} else if member.Length == "1" {
1228			// TODO(b/372341855): Figure out what we really need to do in this case.
1229		} else if member.Length != "" && member.Length != "null-terminated" && !strings.HasSuffix(member.Length, ",null-terminated") {
1230			if length, ok := field_map[member.Length]; ok {
1231				field_map[member.Name].length = length
1232			} else {
1233				return nil, errors.New("Unexpected len field in \"" + member.Name + "\"")
1234			}
1235		}
1236	}
1237	result = make([]cpp_types.FieldInfo, len(fields_info))
1238	for index, field_info := range fields_info {
1239		result[index] = field_info
1240	}
1241	return result, nil
1242}
1243
1244var unknownType = errors.New("Couldn't find type")
1245
1246func elementFromRawXML(element_name string, raw_XML string) (string, error) {
1247	opening_tag := "<" + element_name + ">"
1248	closing_tag := "</" + element_name + ">"
1249	if strings.Count(raw_XML, opening_tag) != 1 {
1250		return "", errors.New("Couldn't determine element \"" + element_name + "\" from \"" + raw_XML + "\"")
1251	}
1252	if strings.Count(raw_XML, closing_tag) != 1 {
1253		return "", errors.New("Couldn't determine element \"" + element_name + "\" from \"" + raw_XML + "\"")
1254	}
1255	return strings.Split(strings.Split(
1256		raw_XML, opening_tag)[1], closing_tag)[0], nil
1257}
1258
1259func parseEnumValues(registry *registry) (map[string]*enumFieldInfo, map[string][]*enumFieldInfo, error) {
1260	enum_values := make(map[string]*enumFieldInfo)
1261	enum_types := make(map[string][]*enumFieldInfo)
1262
1263	for enum_idx := range registry.Enums {
1264		enum := &registry.Enums[enum_idx]
1265		for enum_field_idx := range enum.EnumFields {
1266			enum_field := &enum.EnumFields[enum_field_idx]
1267			if _, ok := enum_values[enum_field.Name]; ok {
1268				return nil, nil, errors.New("Duplicated enum value \"" + enum.Name + "\"")
1269			}
1270			enum_values[enum_field.Name] = enum_field
1271			if value, ok := enum_types[enum.Name]; ok {
1272				enum_types[enum.Name] = append(value, enum_field)
1273			} else {
1274				enum_types[enum.Name] = append([]*enumFieldInfo{}, enum_field)
1275			}
1276		}
1277	}
1278	for feature_idx := range registry.Features {
1279		feature := &registry.Features[feature_idx]
1280		for enum_field_idx := range feature.EnumFields {
1281			enum_field := &feature.EnumFields[enum_field_idx]
1282			if enum_field.Extends != "" {
1283				if _, ok := enum_values[enum_field.Name]; ok {
1284					return nil, nil, errors.New("Duplicated enum value \"" + enum_field.Name + "\"")
1285				}
1286				enum_values[enum_field.Name] = enum_field
1287				enum_types[enum_field.Extends] = append(enum_types[enum_field.Extends], enum_field)
1288			}
1289		}
1290	}
1291	for extension_idx := range registry.Extensions {
1292		extension := &registry.Extensions[extension_idx]
1293		for requires_idx := range extension.Requires {
1294			requires := &extension.Requires[requires_idx]
1295			for enum_field_idx := range requires.EnumFields {
1296				enum_field := &requires.EnumFields[enum_field_idx]
1297				if enum_field.ExtID == 0 {
1298					enum_field.ExtID = extension.ID
1299				}
1300				if enum_field.Extends != "" {
1301					if old_enum_filed, ok := enum_values[enum_field.Name]; ok {
1302						// Some values are declared twice, once as feature and once as extension.
1303						// It's Ok as long as values match.
1304						if enum_field.Alias != "" && enum_field.Alias == old_enum_filed.Alias {
1305							continue
1306						}
1307						if enum_field.Alias == "" || old_enum_filed.Alias == "" {
1308							continue
1309						}
1310						value, err1 := enumFieldValue(enum_field, nil)
1311						old_value, err2 := enumFieldValue(old_enum_filed, nil)
1312						if value == old_value && err1 == nil && err2 == nil {
1313							continue
1314						}
1315						return nil, nil, errors.New("Duplicated enum value \"" + enum_field.Name + "\"")
1316					}
1317					enum_values[enum_field.Name] = enum_field
1318					enum_types[enum_field.Extends] = append(enum_types[enum_field.Extends], enum_field)
1319				}
1320			}
1321		}
1322	}
1323	return enum_values, enum_types, nil
1324}
1325
1326func enumFieldValue(enum_field *enumFieldInfo, all_enum_fields map[string]*enumFieldInfo) (int64, error) {
1327	if enum_field.Value != "" {
1328		if strings.HasPrefix(enum_field.Value, "0x") {
1329			return strconv.ParseInt(enum_field.Value[2:], 16, 64)
1330		}
1331		return strconv.ParseInt(enum_field.Value, 10, 64)
1332	}
1333	if enum_field.BitPos != "" {
1334		result, err := strconv.ParseInt(enum_field.BitPos, 10, 64)
1335		if err != nil {
1336			return 0, err
1337		}
1338		return 1 << result, nil
1339	}
1340	if enum_field.Alias != "" {
1341		return enumFieldValue(all_enum_fields[enum_field.Alias], all_enum_fields)
1342	}
1343	var result = 1000000000 + (enum_field.ExtID-1)*1000 + enum_field.Offset
1344	if enum_field.Dir == "" {
1345		return result, nil
1346	}
1347	return -result, nil
1348}
1349